The R Project SVN R

Rev

Rev 2123 | Rev 2679 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 r 1
/*
1160 maechler 2
 *  R : A Computer Language for Statistical Data Analysis
2 r 3
 *  Copyright (C) 1995, 1996, 1997 Robert Gentleman and Ross Ihaka
4
 *
5
 *  This source code module:
2028 ihaka 6
 *  Copyright (C) 1997, 1998 Paul Murrell and Ross Ihaka
2 r 7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  (at your option) any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program; if not, write to the Free Software
20
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
 */
22
 
23
#include "Mathlib.h"
24
#include "Graphics.h"
25
#include "Defn.h"
2028 ihaka 26
#include "ctype.h"
1926 ihaka 27
 
2028 ihaka 28
/* The R graphics device */
2 r 29
 
2028 ihaka 30
static DevDesc *MathDevice;
31
static unsigned int BoxColor;
32
static unsigned int TextColor;
33
static double BaseCex = 1;
34
static int MetricUnit = INCHES;
581 paul 35
 
2028 ihaka 36
/* Font Definitions */
2 r 37
 
2028 ihaka 38
typedef enum {
39
    PlainFont      = 1,
40
    BoldFont       = 2,
41
    ItalicFont     = 3,
42
    BoldItalicFont = 4,
43
    SymbolFont     = 5,
44
} FontType;
45
 
2122 maechler 46
/*
2028 ihaka 47
 *  Italic Correction Factor
48
 *
49
 *  The correction for a character is computed as ItalicFactor
50
 *  times the height (above the baseline) of the character's
51
 *  bounding box.
52
 *
53
 */
54
 
55
static double ItalicFactor = 0.15;
56
 
57
/* Drawing basics */
58
 
59
static double ReferenceX;
60
static double ReferenceY;
61
static double CurrentX;
62
static double CurrentY;
63
static double CurrentAngle;
64
static double CosAngle;
65
static double SinAngle;
66
 
67
 
68
/* Convert CurrentX and CurrentY from */
69
/* 0 angle to and CurrentAngle */
70
 
71
static double ConvertedX()
2 r 72
{
2028 ihaka 73
    double rotatedX = ReferenceX +
74
	(CurrentX - ReferenceX) * CosAngle -
75
	(CurrentY - ReferenceY) * SinAngle;
76
    return rotatedX;
2 r 77
}
78
 
2028 ihaka 79
static double ConvertedY()
80
{
81
    double rotatedY = ReferenceY +
82
	(CurrentY - ReferenceY) * CosAngle +
83
	(CurrentX - ReferenceX) * SinAngle;
84
    return rotatedY;
85
}
2 r 86
 
2028 ihaka 87
static void MoveAcross(double xamount)
2 r 88
{
2028 ihaka 89
    CurrentX += xamount;
2 r 90
}
91
 
2028 ihaka 92
static void MoveUp(double yamount)
93
{
94
    CurrentY += yamount;
95
}
2 r 96
 
2028 ihaka 97
static void MoveTo(double x, double y)
2 r 98
{
2028 ihaka 99
    CurrentX = x;
100
    CurrentY = y;
2 r 101
}
102
 
2028 ihaka 103
/* Basic Font Properties */
104
 
2105 ihaka 105
#ifdef OLD
2028 ihaka 106
static double FontHeight()
2 r 107
{
2028 ihaka 108
    double height, depth, width;
109
    GMetricInfo(0, &height, &depth, &width, MetricUnit, MathDevice);
110
    return height + depth;
2 r 111
}
2105 ihaka 112
#endif
2 r 113
 
2028 ihaka 114
static double xHeight()
2 r 115
{
2028 ihaka 116
    double height, depth, width;
117
    GMetricInfo('x', &height, &depth, &width, MetricUnit, MathDevice);
118
    return height;
119
}
2 r 120
 
2028 ihaka 121
static double XHeight()
122
{
123
    double height, depth, width;
124
    GMetricInfo('X', &height, &depth, &width, MetricUnit, MathDevice);
125
    return height;
2 r 126
}
127
 
2028 ihaka 128
static double AxisHeight()
2 r 129
{
2028 ihaka 130
    double height, depth, width;
131
    GMetricInfo('+', &height, &depth, &width, MetricUnit, MathDevice);
132
    return 0.5 * height;
2 r 133
}
134
 
2028 ihaka 135
static double Quad()
2 r 136
{
2028 ihaka 137
    double height, depth, width;
138
    GMetricInfo('M', &height, &depth, &width, MetricUnit, MathDevice);
139
    return width;
140
}
141
 
2105 ihaka 142
/* The height of digits */
143
static double FigHeight()
144
{
145
    double height, depth, width;
146
    GMetricInfo('0', &height, &depth, &width, MetricUnit, MathDevice);
147
    return height;
148
}
149
 
150
/* Depth of lower case descenders */
151
static double DescDepth()
152
{
153
    double height, depth, width;
154
    GMetricInfo('g', &height, &depth, &width, MetricUnit, MathDevice);
155
    return depth;
156
}
157
 
2124 maechler 158
#ifdef NOT_used_currently/*-- out 'def'  (-Wall) --*/
2105 ihaka 159
static double AscHeight()
160
{
161
    double height, depth, width, save;
162
    GMetricInfo('d', &height, &depth, &width, MetricUnit, MathDevice);
163
    save = height;
164
    GMetricInfo('a', &height, &depth, &width, MetricUnit, MathDevice);
165
    return save - height;
166
}
2124 maechler 167
#endif
2105 ihaka 168
/* Thickness of rules */
169
static double RuleThickness()
170
{
171
    return 0.015;
172
}
173
 
2028 ihaka 174
static double ThinSpace()
175
{
176
    double height, depth, width;
177
    static double OneSixth = 0.16666666666666666666;
178
    GMetricInfo('M', &height, &depth, &width, MetricUnit, MathDevice);
179
    return OneSixth * width;
180
}
181
 
182
static double MediumSpace()
183
{
184
    double height, depth, width;
185
    static double TwoNinths = 0.22222222222222222222;
186
    GMetricInfo('M', &height, &depth, &width, MetricUnit, MathDevice);
187
    return TwoNinths * width;
188
}
189
 
190
static double ThickSpace()
191
{
192
    double height, depth, width;
193
    static double FiveEighteenths = 0.27777777777777777777;
194
    GMetricInfo('M', &height, &depth, &width, MetricUnit, MathDevice);
195
    return FiveEighteenths * width;
196
}
197
 
198
static double MuSpace()
199
{
200
    double height, depth, width;
201
    static double OneEighteenth = 0.05555555555555555555;
202
    GMetricInfo('M', &height, &depth, &width, MetricUnit, MathDevice);
2122 maechler 203
    return OneEighteenth * width;
2028 ihaka 204
}
205
 
206
 
207
/*
208
 *  Mathematics Layout Parameters
209
 *
2123 maechler 210
 *  The TeXBook, Appendix G, Page 447.
2028 ihaka 211
 *
2105 ihaka 212
 *  These values are based on an inspection of TeX metafont files
213
 *  together with some visual simplification.
2028 ihaka 214
 *
2105 ihaka 215
 *  Note : The values are ``optimised'' for PostScript.
216
 *
2028 ihaka 217
 */
218
 
219
typedef enum {
2105 ihaka 220
    sigma2,  sigma5,  sigma6,  sigma8,  sigma9,  sigma10, sigma11,
221
    sigma12, sigma13, sigma14, sigma15, sigma16, sigma17, sigma18,
222
    sigma19, sigma20, sigma21, sigma22, xi8, xi9, xi10, xi11, xi12, xi13
2028 ihaka 223
}
224
TEXPAR;
225
 
2105 ihaka 226
#define SUBS           0.7
2028 ihaka 227
 
228
static double TeX(TEXPAR which)
229
{
230
    switch(which) {
231
    case sigma2:  /* space */
232
    case sigma5:  /* x_height */
233
	return xHeight();
234
 
235
    case sigma6:  /* quad */
236
	return Quad();
237
 
238
    case sigma8:  /* num1 */
2105 ihaka 239
	return AxisHeight()
240
	    + 3.51 * RuleThickness()
241
	    + 0.15 * XHeight()          /* 54/36 * 0.1 */
242
	    + SUBS * DescDepth();
2028 ihaka 243
    case sigma9:  /* num2 */
2105 ihaka 244
	return AxisHeight()
245
	    + 1.51 * RuleThickness()
246
	    + 0.08333333 * XHeight();   /* 30/36 * 0.1 */
2028 ihaka 247
    case sigma10: /* num3 */
2105 ihaka 248
	return AxisHeight()
249
	    + 1.51 * RuleThickness()
250
	    + 0.1333333 * XHeight();    /* 48/36 * 0.1 */
2028 ihaka 251
    case sigma11: /* denom1 */
2105 ihaka 252
	return  - AxisHeight()
253
	    + 3.51 * RuleThickness()
254
	    + SUBS * FigHeight()
255
	    + 0.344444 * XHeight();     /* 124/36 * 0.1 */
2028 ihaka 256
    case sigma12: /* denom2 */
2105 ihaka 257
	return  - AxisHeight()
258
	    + 1.51 * RuleThickness()
259
	    + SUBS * FigHeight()
260
	    + 0.08333333 * XHeight();   /* 30/36 * 0.1 */
2028 ihaka 261
 
262
    case sigma13: /* sup1 */
2105 ihaka 263
	return 0.95 * xHeight();
2028 ihaka 264
    case sigma14: /* sup2 */
2105 ihaka 265
	return 0.825 * xHeight();
2028 ihaka 266
    case sigma15: /* sup3 */
2105 ihaka 267
	return 0.7 * xHeight();
2028 ihaka 268
 
269
    case sigma16: /* sub1 */
2105 ihaka 270
	return 0.35 * xHeight();
2028 ihaka 271
    case sigma17: /* sub2 */
2105 ihaka 272
	return 0.45 * XHeight();
2028 ihaka 273
 
274
    case sigma18: /* sup_drop */
2105 ihaka 275
	return 0.3861111 * XHeight();
2028 ihaka 276
 
277
    case sigma19: /* sub_drop */
2105 ihaka 278
	return 0.05 * XHeight();
2028 ihaka 279
 
280
    case sigma20: /* delim1 */
2105 ihaka 281
	return 2.39 * XHeight();
2028 ihaka 282
    case sigma21: /* delim2 */
2105 ihaka 283
	return 1.01 *XHeight();
2028 ihaka 284
 
285
    case sigma22: /* axis_height */
286
	return AxisHeight();
287
 
288
    case xi8:     /* default_rule_thickness */
2105 ihaka 289
	return RuleThickness();
2028 ihaka 290
	break;
291
 
292
    case xi9:     /* big_op_spacing1 */
293
    case xi10:    /* big_op_spacing2 */
294
    case xi11:    /* big_op_spacing3 */
295
    case xi12:    /* big_op_spacing4 */
296
    case xi13:    /* big_op_spacing5 */
297
	return 0.15 * XHeight();
298
    }
299
}
300
 
301
/*
302
 *  TeX Math Styles
303
 *
304
 *  The TeXBook, Appendix G, Page 441.
305
 *
306
 */
307
 
308
typedef enum {
309
    STYLE_SS1 = 1,
310
    STYLE_SS  = 2,
311
    STYLE_S1  = 3,
312
    STYLE_S   = 4,
313
    STYLE_T1  = 5,
314
    STYLE_T   = 6,
315
    STYLE_D1  = 7,
316
    STYLE_D   = 8
317
} STYLE;
318
 
319
static STYLE CurrentStyle;
320
 
321
static STYLE GetStyle()
322
{
323
    return CurrentStyle;
324
}
325
 
326
static void SetStyle(STYLE newstyle)
327
{
2122 maechler 328
    switch (newstyle) {
2028 ihaka 329
    case STYLE_D:
330
    case STYLE_T:
331
    case STYLE_D1:
332
    case STYLE_T1:
333
	MathDevice->gp.cex = 1.0 * BaseCex;
334
	break;
335
    case STYLE_S:
336
    case STYLE_S1:
337
	MathDevice->gp.cex = 0.7 * BaseCex;
338
	break;
339
    case STYLE_SS:
340
    case STYLE_SS1:
341
	MathDevice->gp.cex = 0.5 * BaseCex;
342
	break;
343
    default:
344
	error("invalid math style encountered\n");
345
    }
346
    CurrentStyle = newstyle;
347
}
348
 
349
static void SetPrimeStyle(STYLE style)
350
{
351
    switch (style) {
352
    case STYLE_D:
353
    case STYLE_D1:
354
	SetStyle(STYLE_D1);
355
	break;
356
    case STYLE_T:
357
    case STYLE_T1:
358
	SetStyle(STYLE_T1);
359
	break;
360
    case STYLE_S:
361
    case STYLE_S1:
362
	SetStyle(STYLE_S1);
363
	break;
364
    case STYLE_SS:
365
    case STYLE_SS1:
366
	SetStyle(STYLE_SS1);
367
	break;
368
    }
369
}
370
 
371
static void SetSupStyle(STYLE style)
372
{
373
    switch (style) {
374
    case STYLE_D:
375
    case STYLE_T:
376
	SetStyle(STYLE_S);
377
	break;
378
    case STYLE_D1:
379
    case STYLE_T1:
380
	SetStyle(STYLE_S1);
381
	break;
382
    case STYLE_S:
383
    case STYLE_SS:
384
	SetStyle(STYLE_SS);
385
	break;
386
    case STYLE_S1:
387
    case STYLE_SS1:
388
	SetStyle(STYLE_SS1);
389
	break;
390
    }
391
}
392
 
393
static void SetSubStyle(STYLE style)
394
{
395
    switch (style) {
396
    case STYLE_D:
397
    case STYLE_T:
398
    case STYLE_D1:
399
    case STYLE_T1:
400
	SetStyle(STYLE_S1);
401
	break;
402
    case STYLE_S:
403
    case STYLE_SS:
404
    case STYLE_S1:
405
    case STYLE_SS1:
406
	SetStyle(STYLE_SS1);
407
	break;
408
    }
409
}
410
 
411
static void SetNumStyle(STYLE style)
412
{
413
    switch (style) {
414
    case STYLE_D:
415
	SetStyle(STYLE_T);
416
	break;
417
    case STYLE_D1:
418
	SetStyle(STYLE_T1);
419
	break;
420
    default:
421
	SetSupStyle(style);
422
    }
423
}
424
 
425
static void SetDenomStyle(STYLE style)
426
{
427
    if (style > STYLE_T)
428
	SetStyle(STYLE_T1);
1839 ihaka 429
    else
2028 ihaka 430
	SetSubStyle(style);
2 r 431
}
432
 
2028 ihaka 433
static int IsCompactStyle(STYLE style)
2 r 434
{
2028 ihaka 435
    switch (style) {
436
    case STYLE_D1:
437
    case STYLE_T1:
438
    case STYLE_S1:
439
    case STYLE_SS1:
440
	return 1;
441
    default:
442
	return 0;
443
    }
2 r 444
}
445
 
2028 ihaka 446
 
447
#ifdef max
448
#undef max
449
#endif
450
/* Return maximum of two doubles. */
451
static double max(double x, double y)
2 r 452
{
2028 ihaka 453
    if (x > y) return x;
454
    else return y;
2 r 455
}
456
 
2028 ihaka 457
 
458
/* Bounding Boxes */
459
/* These including italic corrections and an */
460
/* indication of whether the nucleus was simple. */
461
 
462
typedef struct {
463
    double height;
464
    double depth;
465
    double width;
466
    double italic;
467
    int simple;
468
} BBOX;
469
 
470
 
471
#define bboxHeight(bbox) bbox.height
472
#define bboxDepth(bbox) bbox.depth
473
#define bboxWidth(bbox) bbox.width
474
#define bboxItalic(bbox) bbox.italic
475
#define bboxSimple(bbox) bbox.simple
476
 
477
 
478
static BBOX MakeBBox(double height, double depth, double width)
2 r 479
{
2028 ihaka 480
    BBOX bbox;
481
    bboxHeight(bbox) = height;
482
    bboxDepth(bbox)  = depth;
483
    bboxWidth(bbox)  = width;
484
    bboxItalic(bbox) = 0;
485
    bboxSimple(bbox) = 0;
486
    return bbox;
2 r 487
}
488
 
2028 ihaka 489
static BBOX NullBBox()
2 r 490
{
2028 ihaka 491
    BBOX bbox;
492
    bboxHeight(bbox) = 0;
493
    bboxDepth(bbox)  = 0;
494
    bboxWidth(bbox)  = 0;
495
    bboxItalic(bbox) = 0;
496
    bboxSimple(bbox) = 0;
497
    return bbox;
2 r 498
}
499
 
2028 ihaka 500
static BBOX ShiftBBox(BBOX bbox1, double shiftV)
2 r 501
{
2028 ihaka 502
    bboxHeight(bbox1) = bboxHeight(bbox1) + shiftV;
503
    bboxDepth(bbox1)  = bboxDepth(bbox1) - shiftV;
504
    bboxWidth(bbox1)  = bboxWidth(bbox1);
505
    bboxItalic(bbox1) = bboxItalic(bbox1);
506
    bboxSimple(bbox1) = bboxSimple(bbox1);
507
    return bbox1;
2 r 508
}
509
 
2028 ihaka 510
static BBOX EnlargeBBox(BBOX bbox, double deltaHeight, double deltaDepth,
511
		      double deltaWidth)
2 r 512
{
2028 ihaka 513
    bboxHeight(bbox) += deltaHeight;
514
    bboxDepth(bbox)  += deltaDepth;
515
    bboxWidth(bbox)  += deltaWidth;
516
    return bbox;
2 r 517
}
518
 
2028 ihaka 519
static BBOX CombineBBoxes(BBOX bbox1, BBOX bbox2)
520
{
521
    bboxHeight(bbox1) = max(bboxHeight(bbox1), bboxHeight(bbox2));
522
    bboxDepth(bbox1)  = max(bboxDepth(bbox1), bboxDepth(bbox2));
523
    bboxWidth(bbox1)  = bboxWidth(bbox1) + bboxWidth(bbox2);
524
    bboxItalic(bbox1) = bboxItalic(bbox2);
525
    bboxSimple(bbox1) = bboxSimple(bbox2);
526
    return bbox1;
527
}
528
 
529
static BBOX CombineAlignedBBoxes(BBOX bbox1, BBOX bbox2)
530
{
531
    bboxHeight(bbox1) = max(bboxHeight(bbox1), bboxHeight(bbox2));
532
    bboxDepth(bbox1)  = max(bboxDepth(bbox1), bboxDepth(bbox2));
533
    bboxWidth(bbox1)  = max(bboxWidth(bbox1), bboxWidth(bbox2));
534
    bboxItalic(bbox1) = 0;
535
    bboxSimple(bbox1) = 0;
536
    return bbox1;
537
}
538
 
539
static BBOX CombineOffsetBBoxes(BBOX bbox1, int italic1,
540
				BBOX bbox2, int italic2,
541
				double xoffset,
542
				double yoffset)
543
{
544
    double width1 = bboxWidth(bbox1) + (italic1 ? bboxItalic(bbox1) : 0);
545
    double width2 = bboxWidth(bbox2) + (italic2 ? bboxItalic(bbox2) : 0);
546
    bboxWidth(bbox1) = max(width1, width2 + xoffset);
547
    bboxHeight(bbox1) = max(bboxHeight(bbox1), bboxHeight(bbox2) + yoffset);
548
    bboxDepth(bbox1) = max(bboxDepth(bbox1), bboxDepth(bbox2) - yoffset);
549
    bboxItalic(bbox1) = 0;
550
    bboxSimple(bbox1) = 0;
551
    return bbox1;
552
}
553
 
554
static double CenterShift(BBOX bbox)
555
{
556
    return 0.5 * (bboxHeight(bbox) - bboxDepth(bbox));
557
}
558
 
2124 maechler 559
#ifdef NOT_used_currently/*-- out 'def'  (-Wall) --*/
2028 ihaka 560
static BBOX DrawBBox(BBOX bbox, double xoffset, double yoffset)
561
{
562
    double xsaved = CurrentX;
563
    double ysaved = CurrentY;
564
    double x[5], y[5];
565
    CurrentX += xoffset;
566
    CurrentY += yoffset;
567
    MathDevice->gp.col = BoxColor;
568
    MoveUp(-bboxDepth(bbox));
569
    x[4] = x[0] = ConvertedX();
570
    y[4] = y[0] = ConvertedY();
571
    MoveAcross(bboxWidth(bbox));
572
    x[1] = ConvertedX();
573
    y[1] = ConvertedY();
574
    MoveUp(bboxHeight(bbox) + bboxDepth(bbox));
575
    x[2] = ConvertedX();
576
    y[2] = ConvertedY();
577
    MoveAcross(-bboxWidth(bbox));
578
    x[3] = ConvertedX();
579
    y[3] = ConvertedY();
580
    GPolyline(5, x, y, INCHES, MathDevice);
581
    MoveTo(xsaved, ysaved);
582
    MathDevice->gp.col = TextColor;
583
    return bbox;
584
}
2124 maechler 585
#endif
2028 ihaka 586
 
587
typedef struct {
588
    char *name;
589
    int code;
590
} SymTab;
591
 
592
/* Determine a match between symbol name and string. */
593
 
594
static int NameMatch(SEXP expr, char *aString)
595
{
596
    return !strcmp(CHAR(PRINTNAME(expr)), aString);
597
}
598
 
599
static int StringMatch(SEXP expr, char *aString)
600
{
601
    return !strcmp(CHAR(STRING(expr)[0]), aString);
602
}
603
/* Code to determine the ascii code corresponding */
604
/* to an element of a mathematical expression. */
605
 
606
#define A_HAT             94
607
#define A_TILDE          126
608
 
609
#define S_SPACE           32
610
#define S_PARENLEFT       40
611
#define S_PARENRIGHT      41
612
#define S_ASTERISKMATH    42
613
#define S_COMMA           44
614
#define S_SLASH           47
615
#define S_RADICALEX       96
616
#define S_FRACTION       164
617
#define S_ELLIPSIS       188
618
#define S_INTERSECTION   199
619
#define S_UNION          200
620
#define S_PRODUCT        213
621
#define S_RADICAL        214
622
#define S_SUM            229
623
#define S_INTEGRAL       242
624
#define S_BRACKETLEFTTP  233
625
#define S_BRACKETLEFTBT  235
626
#define S_BRACKETRIGHTTP 249
627
#define S_BRACKETRIGHTBT 251
628
 
629
#define N_LIM           1001
630
#define N_LIMINF        1002
631
#define N_LIMSUP        1003
632
#define N_INF           1004
633
#define N_SUP           1005
634
#define N_MIN           1006
635
#define N_MAX           1007
636
 
637
 
638
/* The Full Adobe Symbol Font */
639
 
2 r 640
static struct {
1839 ihaka 641
    char *name;
642
    int code;
643
}
1926 ihaka 644
SymbolTable[] = {
2028 ihaka 645
    "space",          32,
646
    "exclam",         33,
647
    "universal",      34,
648
    "numbersign",     35,
649
    "existential",    36,
650
    "percent",        37,
651
    "ampersand",      38,
652
    "suchthat",       39,
653
    "parenleft",      40,
654
    "parenright",     41,
655
    "asteriskmath",   42,
656
    "plus",           43,
657
    "comma",          44,
658
    "minus",          45,
659
    "period",         46,
660
    "slash",          47,
661
    "0",              48,
662
    "1",              49,
663
    "2",              50,
664
    "3",              51,
665
    "4",              52,
666
    "5",              53,
667
    "6",              54,
668
    "7",              55,
669
    "8",              56,
670
    "9",              57,
671
    "colon",          58,
672
    "semicolon",      59,
673
    "less",           60,
674
    "equal",          61,
675
    "greater",        62,
676
    "question",       63,
677
    "congruent",      64,
678
 
1926 ihaka 679
    "Alpha",          65,    /* Upper Case Greek Characters */
680
    "Beta",           66,
681
    "Chi",            67,
682
    "Delta",          68,
683
    "Epsilon",        69,
684
    "Phi",            70,
685
    "Gamma",          71,
686
    "Eta",            72,
687
    "Iota",           73,
2028 ihaka 688
    "theta1",         74,
1926 ihaka 689
    "Kappa",          75,
690
    "Lambda",         76,
691
    "Mu",             77,
692
    "Nu",             78,
693
    "Omicron",        79,
694
    "Pi",             80,
695
    "Theta",          81,
696
    "Rho",            82,
697
    "Sigma",          83,
698
    "Tau",            84,
699
    "Upsilon",        85,
700
    "sigma1",         86,
701
    "Omega",          87,
702
    "Xi",             88,
703
    "Psi",            89,
704
    "Zeta",           90,
2 r 705
 
2028 ihaka 706
    "bracketleft",    91,    /* Miscellaneous Special Characters */
707
    "therefore",      92,
708
    "bracketright",   93,
709
    "perpendicular",  94,
710
    "underscore",     95,
711
    "radicalex",      96,
712
 
1926 ihaka 713
    "alpha",          97,    /* Lower Case Greek Characters */
714
    "beta",           98,
715
    "chi",            99,
716
    "delta",         100,
717
    "epsilon",       101,
718
    "phi",           102,
719
    "gamma",         103,
720
    "eta",           104,
721
    "iota",          105,
722
    "phi1",          106,
723
    "kappa",         107,
724
    "lambda",        108,
725
    "mu",            109,
726
    "nu",            110,
727
    "omicron",       111,
728
    "pi",            112,
729
    "theta",         113,
730
    "rho",           114,
731
    "sigma",         115,
732
    "tau",           116,
733
    "upsilon",       117,
734
    "omega1",        118,
735
    "omega",         119,
736
    "xi",            120,
737
    "psi",           121,
738
    "zeta",          122,
2 r 739
 
2028 ihaka 740
    "braceleft",     123,    /* Miscellaneous Special Characters */
741
    "bar",           124,
742
    "braceright",    125,
743
    "similar",       126,
744
 
745
    "Upsilon1",      161,    /* Lone Greek */
1926 ihaka 746
    "minute",        162,
2028 ihaka 747
    "lessequal",     163,
748
    "fraction",      164,
1926 ihaka 749
    "infinity",      165,
2028 ihaka 750
    "florin",        166,
1926 ihaka 751
    "club",          167,
752
    "diamond",       168,
753
    "heart",         169,
754
    "spade",         170,
2028 ihaka 755
    "arrowboth",     171,
756
    "arrowleft",     172,
757
    "arrowup",       173,
758
    "arrowright",    174,
759
    "arrowdown",     175,
1926 ihaka 760
    "degree",        176,
2028 ihaka 761
    "plusminus",     177,
1926 ihaka 762
    "second",        178,
2028 ihaka 763
    "greaterequal",  179,
764
    "multiply",      180,
765
    "proportional",  181,
1926 ihaka 766
    "partialdiff",   182,
767
    "bullet",        183,
2028 ihaka 768
    "divide",        184,
769
    "notequal",      185,
770
    "equivalence",   186,
771
    "approxequal",   187,
1926 ihaka 772
    "ellipsis",      188,
2028 ihaka 773
    "arrowvertex",   189,
774
    "arrowhorizex",  190,
775
    "carriagereturn",191,
1926 ihaka 776
    "aleph",         192,
777
    "Ifraktur",      193,
778
    "Rfraktur",      194,
779
    "weierstrass",   195,
2028 ihaka 780
    "circlemultiply",196,
781
    "circleplus",    197,
1926 ihaka 782
    "emptyset",      198,
2028 ihaka 783
    "intersection",  199,
784
    "union",         200,
785
    "propersuperset",201,
786
    "reflexsuperset",202,
787
    "notsubset",     203,
788
    "propersubset",  204,
789
    "reflexsubset",  205,
790
    "element",       206,
791
    "notelement",    207,
1926 ihaka 792
    "angle",         208,
793
    "gradient",      209,
2028 ihaka 794
    "registerserif", 210,
795
    "copyrightserif",211,
796
    "trademarkserif",212,
797
    "product",       213,
798
    "radical",       214,
799
    "dotmath",       215,
800
    "logicaland",    217,
801
    "logicalor",     218,
802
    "arrowdblboth",  219,
803
    "arrowdblleft",  220,
804
    "arrowdblup",    221,
805
    "arrowdblright", 222,
806
    "arrowdbldown",  223,
807
    "lozenge",       224,
808
    "angleleft",     225,
809
    "registersans",  226,
810
    "copyrightsans", 227,
811
    "trademarksans", 228,
812
    "summation",     229,
813
    "parenlefttp",   230,
814
    "parenleftex",   231,
815
    "parenleftbt",   232,
816
    "bracketlefttp", 233,
817
    "bracketleftex", 234,
818
    "bracketleftbt", 235,
819
    "bracelefttp",   236,
820
    "braceleftmid",  237,
821
    "braceleftbt",   238,
822
    "braceex",       239,
823
    "angleright",    241,
824
    "integral",      242,
825
    "integraltp",    243,
826
    "integralex",    244,
827
    "integralbt",    245,
828
    "parenrighttp",  246,
829
    "parenrightex",  247,
830
    "parenrightbt",  248,
831
    "bracketrighttp",249,
832
    "bracketrightex",250,
833
    "bracketrightbt",251,
834
    "bracerighttp",  252,
835
    "bracerightmid", 253,
836
    "bracerightbt",  254,
2 r 837
 
1926 ihaka 838
    NULL,              0,
2 r 839
};
840
 
2028 ihaka 841
static int SymbolCode(SEXP expr)
2 r 842
{
1839 ihaka 843
    int i;
1926 ihaka 844
    for (i = 0; SymbolTable[i].code; i++)
2028 ihaka 845
	if (NameMatch(expr, SymbolTable[i].name))
1926 ihaka 846
	    return SymbolTable[i].code;
1839 ihaka 847
    return 0;
848
}
2 r 849
 
2028 ihaka 850
static int TranslatedSymbol(SEXP expr)
1839 ihaka 851
{
2028 ihaka 852
    int code = SymbolCode(expr);
2105 ihaka 853
    if ((0101 <= code && code <= 0132)  ||   /* Greek */
854
	(0141 <= code && code <= 0172)  ||   /* Greek */
855
	code == 0241                    ||   /* Greek */
856
	code == 0242                    ||   /* minute */
857
	code == 0245                    ||   /* infinity */
858
	code == 0260                    ||   /* degree */
859
	code == 0262                    ||   /* second */
2028 ihaka 860
	0)
861
	return code;
862
    else
863
	return 0;
2 r 864
}
865
 
1839 ihaka 866
/* Code to determine the nature of an expression. */
2 r 867
 
2028 ihaka 868
static int FormulaExpression(SEXP expr)
2 r 869
{
1839 ihaka 870
    return (TYPEOF(expr) == LANGSXP);
2 r 871
}
872
 
2028 ihaka 873
static int NameAtom(SEXP expr)
2 r 874
{
1839 ihaka 875
    return (TYPEOF(expr) == SYMSXP);
2 r 876
}
877
 
2028 ihaka 878
static int NumberAtom(SEXP expr)
2 r 879
{
1839 ihaka 880
    return ((TYPEOF(expr) == REALSXP) ||
881
	    (TYPEOF(expr) == INTSXP)  ||
882
	    (TYPEOF(expr) == CPLXSXP));
2 r 883
}
884
 
2028 ihaka 885
static int StringAtom(SEXP expr)
2 r 886
{
1839 ihaka 887
    return (TYPEOF(expr) == STRSXP);
2 r 888
}
889
 
2124 maechler 890
#ifdef NOT_used_currently/*-- out 'def'  (-Wall) --*/
2028 ihaka 891
static int symbolAtom(SEXP expr)
1926 ihaka 892
{
893
    int i;
2028 ihaka 894
    if (NameAtom(expr)) {
895
	for (i = 0; SymbolTable[i].code; i++)
896
	    if (NameMatch(expr, SymbolTable[i].name))
897
		return 1;
898
    }
1926 ihaka 899
    return 0;
2 r 900
}
2124 maechler 901
#endif
2028 ihaka 902
/* Code to determine a font from the */
903
/* nature of the expression */
2 r 904
 
2124 maechler 905
#ifdef NOT_used_currently/*-- out 'def'  (-Wall) --*/
2028 ihaka 906
static FontType CurrentFont = 3;
2124 maechler 907
#endif
2028 ihaka 908
static FontType GetFont()
2 r 909
{
2028 ihaka 910
    return MathDevice->gp.font;
2 r 911
}
912
 
2028 ihaka 913
static FontType SetFont(FontType font)
2 r 914
{
2028 ihaka 915
    FontType prevfont = MathDevice->gp.font;
916
    MathDevice->gp.font = font;
917
    return prevfont;
2 r 918
}
919
 
2028 ihaka 920
static int UsingItalics()
2 r 921
{
2028 ihaka 922
    return (MathDevice->gp.font == ItalicFont ||
923
	    MathDevice->gp.font == BoldItalicFont);
2 r 924
}
925
 
2028 ihaka 926
static BBOX GlyphBBox(int chr)
2 r 927
{
2028 ihaka 928
    BBOX bbox;
929
    double height, depth, width;
930
    GMetricInfo(chr, &height, &depth, &width, MetricUnit, MathDevice);
931
    bboxHeight(bbox) = height;
932
    bboxDepth(bbox)  = depth;
933
    bboxWidth(bbox)  = width;
934
    bboxItalic(bbox) = 0;
935
    bboxSimple(bbox) = 1;
936
    return bbox;
2 r 937
}
938
 
2028 ihaka 939
static BBOX RenderElement(SEXP, int);
940
static BBOX RenderOffsetElement(SEXP, double, double, int);
941
static BBOX RenderExpression(SEXP, int);
942
static BBOX RenderSymbolChar(int, int);
2 r 943
 
944
 
2028 ihaka 945
/*  Code to Generate Bounding Boxes and Draw Formulae.  */
2 r 946
 
2028 ihaka 947
static BBOX RenderItalicCorr(BBOX bbox, int draw)
2 r 948
{
2028 ihaka 949
    if (bboxItalic(bbox) > 0) {
950
	if (draw)
951
	    MoveAcross(bboxItalic(bbox));
952
	bboxWidth(bbox) += bboxItalic(bbox);
953
	bboxItalic(bbox) = 0;
954
    }
955
    return bbox;
2 r 956
}
957
 
2028 ihaka 958
static BBOX RenderGap(double gap, int draw)
2 r 959
{
2028 ihaka 960
    if (draw)
961
	MoveAcross(gap);
962
    return MakeBBox(0, 0, gap);
2 r 963
}
964
 
2028 ihaka 965
/* Draw a Symbol from the Special Font */
2 r 966
 
2028 ihaka 967
static BBOX RenderSymbolChar(int ascii, int draw)
2 r 968
{
2028 ihaka 969
    FontType prev;
970
    BBOX bbox;
971
    char asciiStr[2];
972
    if (ascii == A_HAT || ascii == A_TILDE)
973
	prev = SetFont(PlainFont);
974
    else
975
	prev = SetFont(SymbolFont);
976
    bbox = GlyphBBox(ascii);
977
    if (draw) {
978
	asciiStr[0] = ascii;
979
	asciiStr[1] = '\0';
980
	GText(ConvertedX(), ConvertedY(), INCHES, asciiStr,
981
	      0.0, 0.0, CurrentAngle, MathDevice);
982
	MoveAcross(bboxWidth(bbox));
983
    }
984
    SetFont(prev);
985
    return bbox;
2 r 986
}
987
 
2028 ihaka 988
/* Draw a Symbol String in "Math Mode */
989
/* This code inserts italic corrections after */
990
/* every character. */
2 r 991
 
2028 ihaka 992
static BBOX RenderSymbolStr(char *str, int draw)
2 r 993
{
2028 ihaka 994
    char chr[2];
995
    BBOX glyphBBox;
996
    BBOX resultBBox = NullBBox();
997
    double lastItalicCorr = 0;
998
    FontType prevfont = GetFont();
999
    FontType font = prevfont;
1000
    chr[1] = '\0';
1001
    if (str) {
1002
	char *s = str;
1003
	while (*s) {
1004
	    if (isdigit(*s) && font != PlainFont) {
1005
		font = PlainFont;
1006
		SetFont(PlainFont);
1007
	    }
1008
	    else if (font != prevfont) {
1009
		font = prevfont;
1010
		SetFont(prevfont);
1011
	    }
1012
	    glyphBBox = GlyphBBox(*s);
1013
	    if (UsingItalics())
1014
		bboxItalic(glyphBBox) = ItalicFactor * bboxHeight(glyphBBox);
1015
	    else
1016
		bboxItalic(glyphBBox) = 0;
1017
	    if (draw) {
1018
		chr[0] = *s;
1019
		MoveAcross(lastItalicCorr);
1020
		GText(ConvertedX(), ConvertedY(), INCHES, chr,
1021
		      0.0, 0.0, CurrentAngle, MathDevice);
1022
		MoveAcross(bboxWidth(glyphBBox));
1023
	    }
1024
	    bboxWidth(resultBBox) += lastItalicCorr;
1025
	    resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1026
	    lastItalicCorr = bboxItalic(glyphBBox);
1027
	    s++;
1028
	}
1029
	if (font != prevfont)
1030
	    SetFont(prevfont);
1031
    }
1032
    bboxSimple(resultBBox) = 1;
1033
    return resultBBox;
2 r 1034
}
1035
 
2028 ihaka 1036
/* Code for Character String Atoms. */
2 r 1037
 
2028 ihaka 1038
static BBOX RenderChar(int ascii, int draw)
2 r 1039
{
2028 ihaka 1040
    BBOX bbox;
1041
    char asciiStr[2];
1042
    bbox = GlyphBBox(ascii);
1043
    if (draw) {
1044
	asciiStr[0] = ascii;
1045
	asciiStr[1] = '\0';
1046
	GText(ConvertedX(), ConvertedY(), INCHES, asciiStr,
1047
	      0.0, 0.0, CurrentAngle, MathDevice);
1048
	MoveAcross(bboxWidth(bbox));
1049
    }
1050
    return bbox;
2 r 1051
}
1052
 
2028 ihaka 1053
static BBOX RenderStr(char *str, int draw)
2 r 1054
{
2028 ihaka 1055
    BBOX glyphBBox;
1056
    BBOX resultBBox = NullBBox();
1057
    if (str) {
1058
	char *s = str;
1059
	while (*s) {
1060
	    glyphBBox = GlyphBBox(*s);
1061
	    resultBBox = CombineBBoxes(resultBBox, glyphBBox);
1062
	    s++;
1063
	}
1064
	if (draw) {
1065
	    GText(ConvertedX(), ConvertedY(), INCHES, str,
1066
		  0.0, 0.0, CurrentAngle, MathDevice);
1067
	    MoveAcross(bboxWidth(resultBBox));
1068
	}
1069
	if (UsingItalics())
1070
	    bboxItalic(resultBBox) = ItalicFactor * bboxHeight(glyphBBox);
1071
	else
1072
	    bboxItalic(resultBBox) = 0;
1073
    }
1074
    bboxSimple(resultBBox) = 1;
1075
    return resultBBox;
2 r 1076
}
1077
 
1078
 
2028 ihaka 1079
/* Code for Symbol Font Atoms */
2 r 1080
 
2028 ihaka 1081
static BBOX RenderSymbol(SEXP expr, int draw)
2 r 1082
{
2028 ihaka 1083
    int code;
2124 maechler 1084
    if ((code = TranslatedSymbol(expr)))
2028 ihaka 1085
	return RenderSymbolChar(code, draw);
1086
    else
1087
	return RenderSymbolStr(CHAR(PRINTNAME(expr)), draw);
2 r 1088
}
1089
 
2028 ihaka 1090
static BBOX RenderSymbolString(SEXP expr, int draw)
2 r 1091
{
2028 ihaka 1092
    int code;
2124 maechler 1093
    if ((code = TranslatedSymbol(expr)))
2028 ihaka 1094
	return RenderSymbolChar(code, draw);
1095
    else
1096
	return RenderStr(CHAR(PRINTNAME(expr)), draw);
2 r 1097
}
1098
 
1099
 
2028 ihaka 1100
/* Code for Numeric Atoms */
2 r 1101
 
2028 ihaka 1102
static BBOX RenderNumber(SEXP expr, int draw)
2 r 1103
{
2028 ihaka 1104
    BBOX bbox;
1105
    FontType prevfont = SetFont(PlainFont);
1106
    bbox = RenderStr(CHAR(asChar(expr)), draw);
1107
    SetFont(prevfont);
1108
    return bbox;
2 r 1109
}
1110
 
2028 ihaka 1111
/* Code for String Atoms */
2 r 1112
 
2028 ihaka 1113
static BBOX RenderString(SEXP expr, int draw)
2 r 1114
{
2028 ihaka 1115
    return RenderStr(CHAR(STRING(expr)[0]), draw);
2 r 1116
}
1117
 
2028 ihaka 1118
/* Code for Ellipsis (ldots, cdots, ...) */
2 r 1119
 
2028 ihaka 1120
static int DotsAtom(SEXP expr)
2 r 1121
{
2028 ihaka 1122
    if (NameMatch(expr, "cdots") ||
1123
	NameMatch(expr, "...")   ||
1124
	NameMatch(expr, "ldots"))
1125
            return 1;
1126
    return 0;
2 r 1127
}
1128
 
2028 ihaka 1129
static BBOX RenderDots(SEXP expr, int draw)
2 r 1130
{
2028 ihaka 1131
    BBOX bbox = RenderSymbolChar(S_ELLIPSIS, 0);
1132
    if (NameMatch(expr, "cdots") || NameMatch(expr, "...")) {
1133
	double shift = AxisHeight() - 0.5 * bboxHeight(bbox);
1134
	if (draw) {
1135
	    MoveUp(shift);
1136
	    RenderSymbolChar(S_ELLIPSIS, 1);
1137
	    MoveUp(-shift);
1138
	}
1139
	return ShiftBBox(bbox, shift);
1140
    }
1141
    else {
1142
	if (draw)
1143
	    RenderSymbolChar(S_ELLIPSIS, 1);
1144
	return bbox;
1145
    }
2 r 1146
}
1147
 
2028 ihaka 1148
/*----------------------------------------------------------------------
1149
 *
1150
 *  Code for Atoms
1151
 *
1152
 */
2 r 1153
 
2028 ihaka 1154
static BBOX RenderAtom(SEXP expr, int draw)
2 r 1155
{
2028 ihaka 1156
    if (NameAtom(expr)) {
1157
	if (DotsAtom(expr))
1158
	    return RenderDots(expr, draw);
1159
	else
1160
	    return RenderSymbol(expr, draw);
1161
    }
1162
    else if (NumberAtom(expr))
1163
	return RenderNumber(expr, draw);
1164
    else if (StringAtom(expr))
1165
	return RenderString(expr, draw);
2 r 1166
}
1167
 
1168
 
2028 ihaka 1169
/*----------------------------------------------------------------------
1170
 *
1171
 *  Code for Binary / Unary Operators  (~, +, -, ... )
1172
 *
1173
 *  Note that there are unary and binary ~ s.
1174
 *
1175
 */
2 r 1176
 
2028 ihaka 1177
static int SpaceAtom(SEXP expr)
2 r 1178
{
2028 ihaka 1179
    return NameAtom(expr) && NameMatch(expr, "~");
2 r 1180
}
1181
 
1182
 
2028 ihaka 1183
static BBOX RenderSpace(SEXP expr, int draw)
2 r 1184
{
2124 maechler 1185
 
2028 ihaka 1186
    BBOX opBBox, arg1BBox, arg2BBox;
1187
    int nexpr = length(expr);
2 r 1188
 
2028 ihaka 1189
    if (nexpr == 2) {
1190
	opBBox = RenderSymbolChar(' ', draw);
1191
	arg1BBox = RenderElement(CADR(expr), draw);
1192
	return CombineBBoxes(opBBox, arg1BBox);
1193
    }
1194
    else if (nexpr == 3) {
1195
	arg1BBox = RenderElement(CADR(expr), draw);
1196
	opBBox = RenderSymbolChar(' ', draw);
1197
	arg2BBox = RenderElement(CADDR(expr), draw);
1198
	opBBox = CombineBBoxes(arg1BBox, opBBox);
1199
	opBBox = CombineBBoxes(opBBox, arg2BBox);
1200
	return opBBox;
1201
    }
1839 ihaka 1202
    else
2028 ihaka 1203
	error("invalid mathematical annotation\n");
2 r 1204
 
1205
}
1206
 
2028 ihaka 1207
static SymTab BinTable[] = {
2105 ihaka 1208
    "*",                052,    /* Binary Operators */
1209
    "+",                053,
1210
    "-",                055,
1211
    "/",                057,
1212
    ":",                072,
1213
    "%+-%",            0261,
1214
    "%*%",             0264,
1215
    "%/%",             0270,
1216
    "%intersection%",  0307,
1217
    "%union%",         0310,
1218
    NULL,                 0
2028 ihaka 1219
};
2 r 1220
 
2028 ihaka 1221
static int BinAtom(SEXP expr)
2 r 1222
{
2028 ihaka 1223
    int i;
1224
    for (i = 0; BinTable[i].code; i++)
1225
	if (NameMatch(expr, BinTable[i].name))
1226
	    return BinTable[i].code;
1227
    return 0;
2 r 1228
}
1229
 
2028 ihaka 1230
#define SLASH2
2 r 1231
 
2028 ihaka 1232
static BBOX RenderSlash(int draw)
2 r 1233
{
2028 ihaka 1234
#ifdef SLASH0
1235
    /* The Default Font Character */
1236
    return RenderSymbolChar(S_SLASH, draw);
2 r 1237
#endif
2028 ihaka 1238
#ifdef SLASH1
1239
    /* Symbol Magnify Version */
1240
    double savecex = MathDevice->gp.cex;
1241
    BBOX bbox;
1242
    double height1, height2;
1243
    height1 = bboxHeight(RenderSymbolChar(S_SLASH, 0));
1244
    MathDevice->gp.cex = 1.2 * MathDevice->gp.cex;
1245
    height2 = bboxHeight(RenderSymbolChar(S_SLASH, 0));
1246
    if (draw)
1247
	MoveUp(- 0.5 * (height2 - height1));
1248
    bbox = RenderSymbolChar(S_SLASH, draw);
1249
    if (draw)
1250
	MoveUp(0.5 * (height2 - height1));
1251
    MathDevice->gp.cex = savecex;
1252
    return bbox;
2 r 1253
#endif
2028 ihaka 1254
#ifdef SLASH2
1255
    /* Line Drawing Version */
1256
    double x[2], y[2];
1257
    double depth = 0.5 * TeX(sigma22);
1258
    double height = XHeight() + 0.5 * TeX(sigma22);
1259
    double width = 0.5 * xHeight();
1260
    if (draw) {
1261
	MoveAcross(0.5 * width);
1262
	MoveUp(-depth);
1263
	x[0] = ConvertedX();
1264
	y[0] = ConvertedY();
1265
	MoveAcross(width);
1266
	MoveUp(depth + height);
1267
	x[1] = ConvertedX();
1268
	y[1] = ConvertedY();
1269
	MoveUp(-height);
1270
	GPolyline(2, x, y, INCHES, MathDevice);
1271
	MoveAcross(0.5 * width);
1272
    }
1273
    return MakeBBox(height, depth, 2 * width);
2 r 1274
#endif
2028 ihaka 1275
#ifdef SLASH3
1276
    /* Offset Overprinting - A Failure! */
1277
    BBOX slashBBox = RenderSymbolChar(S_SLASH, 0);
1278
    BBOX ansBBox;
1279
    double height = bboxHeight(slashBBox);
1280
    double depth = bboxDepth(slashBBox);
1281
    double width = bboxWidth(slashBBox);
1282
    double slope = (height + depth) / slope;
1283
    double delta = TeX(sigma22);
1284
    if (draw)
1285
	MoveUp(-delta);
1286
    ansBBox = ShiftBBox(RenderSymbolChar(S_SLASH, draw), -delta);
1287
    MoveUp(2 * delta);
1288
    ansBBox = CombineBBoxes(ansBBox, RenderGap(2 * delta / slope, draw));
1289
    ansBBox = ShiftBBox(RenderSymbolChar(S_SLASH, draw), 2 * delta);
1290
    MoveUp(-delta);
1291
    return ansBBox;
2 r 1292
#endif
1293
}
1294
 
2028 ihaka 1295
static BBOX RenderBin(SEXP expr, int draw)
2 r 1296
{
2028 ihaka 1297
    int op = BinAtom(CAR(expr));
1298
    int nexpr = length(expr);
1299
    BBOX bbox;
1300
    double gap;
2 r 1301
 
2028 ihaka 1302
    if(nexpr == 3) {
1303
	if (op == S_ASTERISKMATH) {
1304
	    bbox = RenderElement(CADR(expr), draw);
1305
	    bbox = RenderItalicCorr(bbox, draw);
1306
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw));
1307
	}
1308
	else if (op == S_SLASH) {
1309
	    gap = 0;
1310
	    bbox = RenderElement(CADR(expr), draw);
1311
	    bbox = RenderItalicCorr(bbox, draw);
1312
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
1313
	    bbox = CombineBBoxes(bbox, RenderSlash(draw));
1314
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
1315
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw));
1316
	}
1317
	else {
2122 maechler 1318
	    gap = (CurrentStyle > STYLE_S) ? MediumSpace() : 0;
2028 ihaka 1319
	    bbox = RenderElement(CADR(expr), draw);
1320
	    bbox = RenderItalicCorr(bbox, draw);
1321
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
1322
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw));
1323
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
1324
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw));
1325
	}
1839 ihaka 1326
    }
2028 ihaka 1327
    else if(nexpr == 2) {
1328
	gap = (CurrentStyle > STYLE_S) ? ThinSpace() : 0;
1329
	bbox = RenderSymbolChar(op, draw);
1330
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
1331
	return CombineBBoxes(bbox, RenderElement(CADR(expr), draw));
1839 ihaka 1332
    }
2028 ihaka 1333
    else error("invalid mathematical annotation\n");
2 r 1334
}
1335
 
1336
 
2028 ihaka 1337
/*----------------------------------------------------------------------
1338
 *
1339
 *  Code for Subscript and Superscipt Expressions
1340
 *
1341
 *  Rules 18, 18a, ..., 18f of the TeXBook.
1342
 *
1343
 */
2 r 1344
 
2028 ihaka 1345
static int SuperAtom(SEXP expr)
2 r 1346
{
2028 ihaka 1347
    return NameAtom(expr) && NameMatch(expr, "^");
2 r 1348
}
1349
 
2028 ihaka 1350
static int SubAtom(SEXP expr)
2 r 1351
{
2028 ihaka 1352
    return NameAtom(expr) && NameMatch(expr, "[");
2 r 1353
}
1354
 
2028 ihaka 1355
/* Note : If all computations are correct */
1356
/* We do not need to save and restore the */
1357
/* current location here.  This is paranoia. */
1358
static BBOX RenderSub(SEXP expr, int draw)
2 r 1359
{
2028 ihaka 1360
    BBOX bodyBBox, subBBox;
1361
    SEXP body = CADR(expr);
1362
    SEXP sub = CADDR(expr);
1363
    STYLE style = GetStyle();
1364
    double savedX = CurrentX;
1365
    double savedY = CurrentY;
2124 maechler 1366
    double v, s5, s16;
2028 ihaka 1367
    bodyBBox = RenderElement(body, draw);
1368
    bodyBBox = RenderItalicCorr(bodyBBox, draw);
1369
    v = bboxSimple(bodyBBox) ? 0 : bboxDepth(bodyBBox) + TeX(sigma19);
1370
    s5 = TeX(sigma5);
1371
    s16 = TeX(sigma16);
1372
    SetSubStyle(style);
1373
    subBBox = RenderElement(sub, 0);
1374
    v = max(max(v, s16), bboxHeight(subBBox) - 0.8 * sigma5);
1375
    subBBox = RenderOffsetElement(sub, 0, -v, draw);
1376
    bodyBBox = CombineBBoxes(bodyBBox, subBBox);
1377
    SetStyle(style);
1378
    if (draw)
1379
	MoveTo(savedX + bboxWidth(bodyBBox), savedY);
1380
    return bodyBBox;
2 r 1381
}
1382
 
2028 ihaka 1383
static BBOX RenderSup(SEXP expr, int draw)
2 r 1384
{
2028 ihaka 1385
    BBOX bodyBBox, subBBox, supBBox;
1386
    SEXP body = CADR(expr);
1387
    SEXP sup = CADDR(expr);
1388
    SEXP sub;
1389
    STYLE style = GetStyle();
1390
    double savedX = CurrentX;
1391
    double savedY = CurrentY;
1392
    double theta, delta, width;
1393
    double u, p;
1394
    double v, s5, s17;
1395
    int haveSub;
1396
    if (FormulaExpression(body) && SubAtom(CAR(body))) {
1397
	sub = CADDR(body);
1398
	body = CADR(body);
1399
	haveSub = 1;
1400
    }
1401
    else haveSub = 0;
1402
    bodyBBox = RenderElement(body, draw);
1403
    delta = bboxItalic(bodyBBox);
1404
    bodyBBox = RenderItalicCorr(bodyBBox, draw);
1405
    width = bboxWidth(bodyBBox);
1406
    if (bboxSimple(bodyBBox)) {
1407
	u = 0;
1408
	v = 0;
1409
    }
1410
    else {
1411
	u = bboxHeight(bodyBBox) - TeX(sigma18);
1412
	v = bboxDepth(bodyBBox) + TeX(sigma19);
1413
    }
1414
    theta = TeX(xi8);
1415
    s5 = TeX(sigma5);
1416
    s17 = TeX(sigma17);
1417
    if (style == STYLE_D)
1418
	p = TeX(sigma13);
1419
    else if (IsCompactStyle(style))
1420
	p = TeX(sigma15);
1839 ihaka 1421
    else
2028 ihaka 1422
	p = TeX(sigma14);
1423
    SetSupStyle(style);
1424
    supBBox = RenderElement(sup, 0);
1425
    u = max(max(u, p), bboxDepth(supBBox) + 0.25 * s5);
2 r 1426
 
2028 ihaka 1427
    if (haveSub) {
1428
	SetSubStyle(style);
1429
	subBBox = RenderElement(sub, 0);
1430
	v = max(v, s17);
1431
	if ((u - bboxDepth(supBBox)) - (bboxHeight(subBBox) - v) < 4 * theta) {
1432
	    double psi = 0.8 * s5 - (u - bboxDepth(supBBox));
1433
	    if (psi > 0) {
1434
		u += psi;
1435
		v -= psi;
1436
	    }
1437
	}
1438
	if (draw)
1439
	    MoveTo(savedX, savedY);
1440
	subBBox = RenderOffsetElement(sub, width, -v, draw);
1441
	if (draw)
1442
	    MoveTo(savedX, savedY);
1443
	SetSupStyle(style);
1444
	supBBox = RenderOffsetElement(sup, width + delta, u, draw);
1445
	bodyBBox = CombineAlignedBBoxes(bodyBBox, subBBox);
1446
	bodyBBox = CombineAlignedBBoxes(bodyBBox, supBBox);
1447
    }
1448
    else {
1449
	supBBox = RenderOffsetElement(sup, 0, u, draw);
1450
	bodyBBox = CombineBBoxes(bodyBBox, supBBox);
1451
    }
1452
    if (draw)
1453
	MoveTo(savedX + bboxWidth(bodyBBox), savedY);
1454
    SetStyle(style);
1455
    return bodyBBox;
2 r 1456
}
1457
 
1458
 
2028 ihaka 1459
/*----------------------------------------------------------------------
1460
 *
1461
 *  Code for Accented Expressions (widehat, bar, widetilde, ...)
1462
 *
1463
 */
2 r 1464
 
2028 ihaka 1465
#define ACCENT_GAP  0.2
1466
#define HAT_HEIGHT  0.3
2 r 1467
 
2028 ihaka 1468
#define NTILDE      8
1469
#define DELTA       0.05
2 r 1470
 
2028 ihaka 1471
static int WideTildeAtom(SEXP expr)
2 r 1472
{
2028 ihaka 1473
    return NameAtom(expr) && NameMatch(expr, "widetilde");
2 r 1474
}
1475
 
2028 ihaka 1476
static BBOX RenderWideTilde(SEXP expr, int draw)
2 r 1477
{
2028 ihaka 1478
    double savedX = CurrentX;
1479
    double savedY = CurrentY;
1480
    BBOX bbox = RenderElement(CADR(expr), draw);
1481
    double height = bboxHeight(bbox);
2124 maechler 1482
    /*double width = bboxWidth(bbox);*/
2028 ihaka 1483
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1484
    double delta = totalwidth * (1 - 2 * DELTA) / NTILDE;
1485
    double start = DELTA * totalwidth;
2105 ihaka 1486
    double accentGap = ACCENT_GAP * XHeight();
1487
    double hatHeight = 0.5 * HAT_HEIGHT * XHeight();
2028 ihaka 1488
    double c = 8 * atan(1.0) / NTILDE;
1489
    double x[NTILDE + 3], y[NTILDE + 3];
1490
    double baseX, baseY, xval, yval;
1491
    int i;
2 r 1492
 
2028 ihaka 1493
    if (draw) {
1494
	baseX = savedX;
1495
	baseY = savedY + height + accentGap;
1496
	MoveTo(baseX, baseY);
1497
	x[0] = ConvertedX();
1498
	y[0] = ConvertedY();
1499
	for (i = 0; i <= NTILDE; i++) {
1500
	    xval = start + i * delta;
1501
	    yval = 0.5 * hatHeight * (sin(c * i) + 1);
1502
	    MoveTo(baseX + xval, baseY + yval);
1503
	    x[i + 1] = ConvertedX();
1504
	    y[i + 1] = ConvertedY();
1505
	}
1506
	MoveTo(baseX + totalwidth, baseY + hatHeight);
1507
	x[NTILDE + 2] = ConvertedX();
1508
	y[NTILDE + 2] = ConvertedY();
1509
	GPolyline(NTILDE + 3, x, y, INCHES, MathDevice);
1510
	MoveTo(savedX + totalwidth, savedY);
1511
    }
1512
    return MakeBBox(height + accentGap + hatHeight,
1513
		    bboxDepth(bbox), totalwidth);
2 r 1514
}
1515
 
2028 ihaka 1516
static int WideHatAtom(SEXP expr)
2 r 1517
{
2028 ihaka 1518
    return NameAtom(expr) && NameMatch(expr, "widehat");
2 r 1519
}
1520
 
2028 ihaka 1521
static BBOX RenderWideHat(SEXP expr, int draw)
2 r 1522
{
2028 ihaka 1523
    double savedX = CurrentX;
1524
    double savedY = CurrentY;
1525
    BBOX bbox = RenderElement(CADR(expr), draw);
2105 ihaka 1526
    double accentGap = ACCENT_GAP * XHeight();
1527
    double hatHeight = HAT_HEIGHT * XHeight();
2028 ihaka 1528
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1529
    double height = bboxHeight(bbox);
1530
    double width = bboxWidth(bbox);
1531
    double x[3], y[3];
2 r 1532
 
2028 ihaka 1533
    if (draw) {
1534
	MoveTo(savedX, savedY + height + accentGap);
1535
	x[0] = ConvertedX();
1536
	y[0] = ConvertedY();
1537
	MoveAcross(0.5 * totalwidth);
1538
	MoveUp(hatHeight);
1539
	x[1] = ConvertedX();
1540
	y[1] = ConvertedY();
1541
	MoveAcross(0.5 * totalwidth);
1542
	MoveUp(-hatHeight);
1543
	x[2] = ConvertedX();
1544
	y[2] = ConvertedY();
1545
	GPolyline(3, x, y, INCHES, MathDevice);
1546
	MoveTo(savedX + width, savedY);
1547
    }
1548
    return EnlargeBBox(bbox, accentGap + hatHeight, 0, 0);
2 r 1549
}
1550
 
2028 ihaka 1551
static int BarAtom(SEXP expr)
2 r 1552
{
2028 ihaka 1553
    return NameAtom(expr) && NameMatch(expr, "bar");
2 r 1554
}
1555
 
2028 ihaka 1556
static BBOX RenderBar(SEXP expr, int draw)
2 r 1557
{
2028 ihaka 1558
    double savedX = CurrentX;
1559
    double savedY = CurrentY;
1560
    BBOX bbox = RenderElement(CADR(expr), draw);
2105 ihaka 1561
    double accentGap = ACCENT_GAP * XHeight();
2124 maechler 1562
    /*double hatHeight = HAT_HEIGHT * XHeight();*/
2028 ihaka 1563
    double height = bboxHeight(bbox);
1564
    double width = bboxWidth(bbox);
2105 ihaka 1565
    double offset = bboxItalic(bbox);
2028 ihaka 1566
    double x[2], y[2];
2 r 1567
 
2028 ihaka 1568
    if (draw) {
2105 ihaka 1569
	MoveTo(savedX + offset, savedY + height + accentGap);
2028 ihaka 1570
	x[0] = ConvertedX();
1571
	y[0] = ConvertedY();
2105 ihaka 1572
	MoveAcross(width);
2028 ihaka 1573
	x[1] = ConvertedX();
1574
	y[1] = ConvertedY();
1575
	GPolyline(2, x, y, INCHES, MathDevice);
1576
	MoveTo(savedX + width, savedY);
1577
    }
1578
    return EnlargeBBox(bbox, accentGap, 0, 0);
2 r 1579
}
1580
 
2028 ihaka 1581
static struct {
1582
    char *name;
1583
    int code;
2 r 1584
}
2028 ihaka 1585
AccentTable[] = {
1586
    "hat",            94,
2105 ihaka 1587
    "ring",          176,
2028 ihaka 1588
    "tilde",         126,
1589
    NULL,              0,
1590
};
2122 maechler 1591
 
2028 ihaka 1592
static int AccentCode(SEXP expr)
2 r 1593
{
2028 ihaka 1594
    int i;
1595
    for (i = 0; AccentTable[i].code; i++)
1596
	if (NameMatch(expr, AccentTable[i].name))
1597
	    return AccentTable[i].code;
1598
    return 0;
2 r 1599
}
1600
 
2028 ihaka 1601
static int AccentAtom(SEXP expr)
2 r 1602
{
2105 ihaka 1603
    return NameAtom(expr) && (AccentCode(expr) != 0);
2 r 1604
}
1605
 
2028 ihaka 1606
static void InvalidAccent(SEXP expr)
2 r 1607
{
2028 ihaka 1608
    errorcall(expr, "invalid accent\n");
2 r 1609
}
1610
 
2028 ihaka 1611
static BBOX RenderAccent(SEXP expr, int draw)
2 r 1612
{
2028 ihaka 1613
    SEXP body, accent;
1614
    double savedX = CurrentX;
1615
    double savedY = CurrentY;
1616
    BBOX bodyBBox, accentBBox;
2105 ihaka 1617
    double xoffset, yoffset, width, italic;
2028 ihaka 1618
    int code;
1619
    if (length(expr) != 2)
1620
	InvalidAccent(expr);
1621
    accent = CAR(expr);
1622
    body = CADR(expr);
2105 ihaka 1623
    code = AccentCode(accent);
1624
    if (code == 0)
2028 ihaka 1625
	InvalidAccent(expr);
2105 ihaka 1626
    bodyBBox = RenderElement(body, 0);
1627
    italic = bboxItalic(bodyBBox);
2028 ihaka 1628
    accentBBox = RenderChar(code, 0);
2105 ihaka 1629
    width = max(bboxWidth(bodyBBox) + bboxItalic(bodyBBox),
1630
		bboxWidth(accentBBox));
1631
    xoffset = 0.5 *(width - bboxWidth(bodyBBox));
1632
    bodyBBox = RenderGap(xoffset, draw);
1633
    bodyBBox = CombineBBoxes(bodyBBox, RenderElement(body, draw));
1634
    bodyBBox = CombineBBoxes(bodyBBox, RenderGap(xoffset, draw));
1635
    MoveTo(savedX, savedY);
1636
    xoffset = 0.5 *(width - bboxWidth(accentBBox))
1637
	+ 0.9 * italic;
1638
    yoffset = bboxHeight(bodyBBox) + bboxDepth(accentBBox) + 0.1 * XHeight();
2028 ihaka 1639
    if (draw) {
1640
	MoveTo(savedX + xoffset, savedY + yoffset);
1641
	RenderChar(code, draw);
1642
    }
1643
    bodyBBox = CombineOffsetBBoxes(bodyBBox, 0, accentBBox, 0,
1644
				   xoffset, yoffset);
2105 ihaka 1645
    MoveTo(savedX + width, savedY);
2028 ihaka 1646
    return bodyBBox;
2 r 1647
}
1648
 
1649
 
2028 ihaka 1650
/*----------------------------------------------------------------------
1651
 *
1652
 *  Code for Fraction Expressions  (over, atop)
1653
 *
1654
 *  Rules 15, 15a, ..., 15e of the TeXBook
1655
 *
1656
 */
2 r 1657
 
2028 ihaka 1658
static void NumDenomVShift(BBOX numBBox, BBOX denomBBox,
1659
			     double *u, double *v)
2 r 1660
{
2028 ihaka 1661
    double a, delta, phi, theta;
1662
    a = TeX(sigma22);
1663
    theta = TeX(xi8);
1664
    if(CurrentStyle > STYLE_T) {
1665
	*u = TeX(sigma8);
1666
	*v = TeX(sigma11);
1667
	phi = 3 * theta;
1668
    }
1669
    else {
1670
	*u = TeX(sigma9);
1671
	*v = TeX(sigma12);
1672
	phi = theta;
1673
    }
1674
    delta = (*u - bboxDepth(numBBox)) - (a + 0.5 * theta);
1675
    if (delta < phi)
2105 ihaka 1676
	*u += (phi - delta) + theta;
2028 ihaka 1677
    delta = (a + 0.5 * theta) - (bboxHeight(denomBBox) - *v);
1678
    if (delta < phi)
2105 ihaka 1679
	*v += (phi - delta) + theta;
2 r 1680
}
1681
 
2028 ihaka 1682
static void NumDenomHShift(BBOX numBBox, BBOX denomBBox,
1683
			   double *numShift, double *denomShift)
2 r 1684
{
2028 ihaka 1685
    double numWidth = bboxWidth(numBBox);
1686
    double denomWidth = bboxWidth(denomBBox);
1687
    if (numWidth > denomWidth) {
1688
	*numShift = 0;
1689
	*denomShift = (numWidth - denomWidth) / 2;
1690
    }
1691
    else {
1692
	*numShift = (denomWidth - numWidth) / 2;
1693
	*denomShift = 0;
1694
    }
2 r 1695
}
1696
 
2028 ihaka 1697
static BBOX RenderFraction(SEXP expr, int rule, int draw)
2 r 1698
{
2028 ihaka 1699
    SEXP numerator = CADR(expr);
1700
    SEXP denominator = CADDR(expr);
2124 maechler 1701
    BBOX numBBox, denomBBox;
2028 ihaka 1702
    double nHShift, dHShift;
1703
    double nVShift, dVShift;
1704
    double width, x[2], y[2];
1705
    double savedX = CurrentX;
1706
    double savedY = CurrentY;
1707
    STYLE style;
2 r 1708
 
2028 ihaka 1709
    style = GetStyle();
1710
    SetNumStyle(style);
1711
    numBBox = RenderItalicCorr(RenderElement(numerator, 0), 0);
1712
    SetDenomStyle(style);
1713
    denomBBox = RenderItalicCorr(RenderElement(denominator, 0), 0);
1714
    SetStyle(style);
2 r 1715
 
2028 ihaka 1716
    width = max(bboxWidth(numBBox), bboxWidth(denomBBox));
1717
    NumDenomHShift(numBBox, denomBBox, &nHShift, &dHShift);
1718
    NumDenomVShift(numBBox, denomBBox, &nVShift, &dVShift);
2 r 1719
 
2028 ihaka 1720
    CurrentX = savedX;
1721
    CurrentY = savedY;
1722
    SetNumStyle(style);
1723
    numBBox = RenderOffsetElement(numerator, nHShift, nVShift, draw);
2 r 1724
 
2028 ihaka 1725
    CurrentX = savedX;
1726
    CurrentY = savedY;
1727
    SetDenomStyle(style);
1728
    denomBBox = RenderOffsetElement(denominator, dHShift, -dVShift, draw);
2 r 1729
 
2028 ihaka 1730
    SetStyle(style);
2 r 1731
 
2028 ihaka 1732
    if (draw) {
1733
	if (rule) {
1734
	    CurrentX = savedX;
1735
	    CurrentY = savedY;
1736
	    MoveUp(AxisHeight());
1737
	    x[0] = ConvertedX();
1738
	    y[0] = ConvertedY();
1739
	    MoveAcross(width);
1740
	    x[1] = ConvertedX();
1741
	    y[1] = ConvertedY();
1742
	    GPolyline(2, x, y, INCHES, MathDevice);
1743
	    MoveUp(-AxisHeight());
1744
	}
1745
	MoveTo(savedX + width, savedY);
1746
    }
1747
    return CombineAlignedBBoxes(numBBox, denomBBox);
2 r 1748
}
1749
 
2028 ihaka 1750
static int OverAtom(SEXP expr)
2 r 1751
{
2105 ihaka 1752
    return NameAtom(expr) &&
1753
        (NameMatch(expr, "over") || NameMatch(expr, "frac"));
2 r 1754
}
1755
 
2028 ihaka 1756
static BBOX RenderOver(SEXP expr, int draw)
2 r 1757
{
2028 ihaka 1758
    return RenderFraction(expr, 1, draw);
2 r 1759
}
1760
 
2028 ihaka 1761
static int AtopAtom(SEXP expr)
2 r 1762
{
2028 ihaka 1763
    return NameAtom(expr) && NameMatch(expr, "atop");
2 r 1764
}
1765
 
2028 ihaka 1766
static BBOX RenderAtop(SEXP expr, int draw)
2 r 1767
{
2028 ihaka 1768
    return RenderFraction(expr, 0, draw);
2 r 1769
}
2105 ihaka 1770
 
2028 ihaka 1771
/*----------------------------------------------------------------------
1772
 *
1773
 *  Code for Grouped Expressions  (e.g. ( ... ))
1774
 *
1775
 *    group(ldelim, body, rdelim)
1776
 *
1777
 *    bgroup(ldelim, body, rdelim)
1778
 *
1779
 */
2 r 1780
 
2105 ihaka 1781
#define DelimSymbolMag 1.25
1782
 
2028 ihaka 1783
static int DelimCode(SEXP expr, SEXP head)
2 r 1784
{
2028 ihaka 1785
    int code = 0;
1786
    if (NameAtom(head)) {
1787
	if (NameMatch(head, "lfloor"))
1788
	    code = S_BRACKETLEFTBT;
1789
	else if (NameMatch(head, "rfloor"))
1790
	    code = S_BRACKETRIGHTBT;
1791
	if (NameMatch(head, "lceil"))
1792
	    code = S_BRACKETLEFTBT;
1793
	else if (NameMatch(head, "rceil"))
1794
	    code = S_BRACKETRIGHTBT;
1795
    }
1796
    else if (StringAtom(head) && length(head) > 0) {
1797
	if (StringMatch(head, "|"))
1798
	    code = '|';
1799
	else if (StringMatch(head, "||"))
1800
	    code = 2;
1801
	else if (StringMatch(head, "("))
1802
	    code = '(';
1803
	else if (StringMatch(head, ")"))
1804
	    code = ')';
1805
	else if (StringMatch(head, "["))
1806
	    code = '[';
1807
	else if (StringMatch(head, "]"))
1808
	    code = ']';
1809
	else if (StringMatch(head, "{"))
1810
	    code = '{';
1811
	else if (StringMatch(head, "}"))
1812
	    code = '}';
1813
	else if (StringMatch(head, "") || StringMatch(head, "."))
1814
	    code = '.';
1815
    }
1816
    if (code == 0)
1817
	errorcall(expr, "invalid group delimiter\n");
1818
    return code;
1016 maechler 1819
}
2 r 1820
 
2105 ihaka 1821
static BBOX RenderDelimiter(int delim, int draw)
1822
{
1823
    BBOX bbox;
1824
    double savecex = MathDevice->gp.cex;
1825
    MathDevice->gp.cex = DelimSymbolMag * MathDevice->gp.cex;
1826
    bbox = RenderSymbolChar(delim, draw);
1827
    MathDevice->gp.cex = savecex;
1828
    return bbox;
1829
}
1830
 
2028 ihaka 1831
static int GroupAtom(SEXP expr)
2 r 1832
{
2028 ihaka 1833
    return NameAtom(expr) && NameMatch(expr, "group");
2 r 1834
}
1835
 
2028 ihaka 1836
static BBOX RenderGroup(SEXP expr, int draw)
2 r 1837
{
2105 ihaka 1838
    double cexSaved = MathDevice->gp.cex;
2028 ihaka 1839
    BBOX bbox;
1840
    int code;
1841
    if (length(expr) != 4)
1842
	errorcall(expr, "invalid group specification\n");
1843
    bbox = NullBBox();
1844
    code = DelimCode(expr, CADR(expr));
2105 ihaka 1845
    MathDevice->gp.cex = DelimSymbolMag * MathDevice->gp.cex;
2028 ihaka 1846
    if (code == 2) {
1847
	bbox = RenderSymbolChar('|', draw);
1848
	bbox = RenderSymbolChar('|', draw);
1849
    }
1850
    else if (code != '.')
1851
	bbox = RenderSymbolChar(code, draw);
2105 ihaka 1852
    MathDevice->gp.cex = cexSaved;
2028 ihaka 1853
    bbox = CombineBBoxes(bbox, RenderElement(CADDR(expr), draw));
1854
    bbox = RenderItalicCorr(bbox, draw);
1855
    code = DelimCode(expr, CADDDR(expr));
2105 ihaka 1856
    MathDevice->gp.cex = DelimSymbolMag * MathDevice->gp.cex;
2028 ihaka 1857
    if (code == 2) {
1858
	bbox = RenderSymbolChar('|', draw);
1859
	bbox = RenderSymbolChar('|', draw);
1860
    }
1861
    else if (code != '.')
1862
	bbox = RenderSymbolChar(code, draw);
2105 ihaka 1863
    MathDevice->gp.cex = cexSaved;
2028 ihaka 1864
    return bbox;
2 r 1865
}
1866
 
2028 ihaka 1867
static int BGroupAtom(SEXP expr)
2 r 1868
{
2028 ihaka 1869
    return NameAtom(expr) && NameMatch(expr, "bgroup");
2 r 1870
}
1871
 
2028 ihaka 1872
static BBOX RenderDelim(int which, double dist, int draw)
2 r 1873
{
2028 ihaka 1874
    double savedX = CurrentX;
1875
    double savedY = CurrentY;
1876
    FontType prev = SetFont(SymbolFont);
1877
    BBOX ansBBox, topBBox, botBBox, extBBox, midBBox;
1878
    int top, bot, ext, mid;
2105 ihaka 1879
    int i, n;
1880
    double topShift, botShift, extShift, midShift;
1881
    double ytop, ybot, extHeight, delta;
2028 ihaka 1882
    double axisHeight = TeX(sigma22);
2 r 1883
 
2028 ihaka 1884
    switch(which) {
1885
    case '.':
1886
	return NullBBox();
1887
	break;
1888
    case '|':
1889
    case 2:
1890
	top = 239; ext = 239; bot = 239; mid = 0;
1891
	break;
1892
    case '(':
1893
	top = 230; ext = 231; bot = 232; mid = 0;
1894
	break;
1895
    case ')':
1896
	top = 246; ext = 247; bot = 248; mid = 0;
1897
	break;
1898
    case '[':
1899
	top = 233; ext = 234; bot = 235; mid = 0;
1900
	break;
1901
    case ']':
1902
	top = 249; ext = 250; bot = 251; mid = 0;
1903
	break;
1904
    case '{':
1905
	top = 236; ext = 239; bot = 238; mid = 237;
2122 maechler 1906
	break;
2028 ihaka 1907
    case '}':
1908
	top = 252; ext = 239; bot = 254; mid = 253;
1909
	break;
1910
    default:
1911
	error("group is incomplete\n");
1912
	break;
1913
    }
1914
    topBBox = GlyphBBox(top);
1915
    extBBox = GlyphBBox(ext);
1916
    botBBox = GlyphBBox(bot);
2105 ihaka 1917
    if (which == '{' || which == '}') {
1918
	if (1.2 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
1919
	    dist = 1.2 * (bboxHeight(topBBox) + bboxDepth(botBBox));
1920
    }
1921
    else {
1922
	if (0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
1923
	    dist = 0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox));
1924
    }
1925
    extHeight = bboxHeight(extBBox) + bboxDepth(extBBox);
2028 ihaka 1926
    topShift = dist - bboxHeight(topBBox) + axisHeight;
1927
    botShift = dist - bboxDepth(botBBox) - axisHeight;
2105 ihaka 1928
    extShift = 0.5 * (bboxHeight(extBBox) - bboxDepth(extBBox));
2028 ihaka 1929
    topBBox = ShiftBBox(topBBox, topShift);
1930
    botBBox = ShiftBBox(botBBox, -botShift);
1931
    ansBBox = CombineAlignedBBoxes(topBBox, botBBox);
2105 ihaka 1932
    if (which == '{' || which == '}') {
1933
	midBBox = GlyphBBox(mid);
1934
	midShift = axisHeight
1935
	    - 0.5 * (bboxHeight(midBBox) - bboxDepth(midBBox));
1936
	midBBox = ShiftBBox(midBBox, midShift);
1937
	ansBBox = CombineAlignedBBoxes(ansBBox, midBBox);
1938
	if (draw) {
1939
	    MoveTo(savedX, savedY + topShift);
1940
	    RenderSymbolChar(top, draw);
1941
	    MoveTo(savedX, savedY + midShift);
2122 maechler 1942
	    RenderSymbolChar(mid, draw);
2105 ihaka 1943
	    MoveTo(savedX, savedY - botShift);
1944
	    RenderSymbolChar(bot, draw);
1945
	    MoveTo(savedX + bboxWidth(ansBBox), savedY);
1946
	}
2028 ihaka 1947
    }
2105 ihaka 1948
    else {
1949
	if (draw) {
1950
	    /* draw the top and bottom elements */
1951
	    MoveTo(savedX, savedY + topShift);
1952
	    RenderSymbolChar(top, draw);
1953
	    MoveTo(savedX, savedY - botShift);
1954
	    RenderSymbolChar(bot, draw);
1955
	    /* now join with extenders */
1956
	    ytop = axisHeight + dist
1957
		- (bboxHeight(topBBox) + bboxDepth(topBBox));
1958
	    ybot = axisHeight - dist
1959
		+ (bboxHeight(botBBox) + bboxDepth(botBBox));
1960
	    n = ceil((ytop - ybot) / (0.99 * extHeight));
1961
	    if (n > 0) {
1962
		delta = (ytop - ybot) / n;
1963
		for (i = 0; i < n; i++) {
1964
		    MoveTo(savedX, savedY + ybot + (i + 0.5) * delta - extShift);
1965
		    RenderSymbolChar(ext, draw);
1966
		}
1967
	    }
1968
	    MoveTo(savedX + bboxWidth(ansBBox), savedY);
2122 maechler 1969
 
2105 ihaka 1970
	}
1971
    }
2028 ihaka 1972
    SetFont(prev);
1973
    return ansBBox;
2 r 1974
}
1975
 
2028 ihaka 1976
static BBOX RenderBGroup(SEXP expr, int draw)
2 r 1977
{
2028 ihaka 1978
    double dist;
2124 maechler 1979
    BBOX bbox;
2028 ihaka 1980
    double axisHeight = TeX(sigma22);
1981
    double extra = 0.2 * xHeight();
1982
    int delim1, delim2;
1983
    if (length(expr) != 4)
1984
	errorcall(expr, "invalid group specification\n");
1985
    bbox = NullBBox();
1986
    delim1 = DelimCode(expr, CADR(expr));
1987
    delim2 = DelimCode(expr, CADDDR(expr));
1988
    bbox = RenderElement(CADDR(expr), 0);
1989
    dist = max(bboxHeight(bbox) - axisHeight, bboxDepth(bbox) + axisHeight);
1990
    bbox = RenderDelim(delim1, dist + extra, draw);
1991
    bbox = CombineBBoxes(bbox,  RenderElement(CADDR(expr), draw));
1992
    bbox = RenderItalicCorr(bbox, draw);
1993
    bbox = CombineBBoxes(bbox,  RenderDelim(delim2, dist + extra, draw));
1994
    return bbox;
2 r 1995
}
1996
 
2028 ihaka 1997
/*----------------------------------------------------------------------
1998
 *
1999
 *  Code for Parenthetic Expressions  (i.e. ( ... ))
2000
 *
2001
 */
2 r 2002
 
2028 ihaka 2003
static int ParenAtom(SEXP expr)
2 r 2004
{
2028 ihaka 2005
    return NameAtom(expr) && NameMatch(expr, "(");
2 r 2006
}
2007
 
2028 ihaka 2008
static BBOX RenderParen(SEXP expr, int draw)
2 r 2009
{
2028 ihaka 2010
    BBOX bbox;
2105 ihaka 2011
    bbox = RenderDelimiter(S_PARENLEFT, draw);
2028 ihaka 2012
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw));
2013
    bbox = RenderItalicCorr(bbox, draw);
2105 ihaka 2014
    return CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw));
2 r 2015
}
2016
 
2028 ihaka 2017
/*----------------------------------------------------------------------
2018
 *
2019
 *  Code for Integral Operators.
2020
 *
2021
 */
2 r 2022
 
2028 ihaka 2023
static int IntAtom(SEXP expr)
2 r 2024
{
2028 ihaka 2025
    return NameAtom(expr) && NameMatch(expr, "integral");
2 r 2026
}
2027
 
1926 ihaka 2028
 
2028 ihaka 2029
static BBOX RenderIntSymbol(int draw)
1926 ihaka 2030
{
2028 ihaka 2031
    double savedX = CurrentX;
2032
    double savedY = CurrentY;
2105 ihaka 2033
    if (GetStyle() > STYLE_T) {
2034
	BBOX bbox1 = RenderSymbolChar(243, 0);
2035
	BBOX bbox2 = RenderSymbolChar(245, 0);
2036
	double shift;
2037
	shift = TeX(sigma22) + 0.99 * bboxDepth(bbox1);
2038
	MoveUp(shift);
2039
	bbox1 = ShiftBBox(RenderSymbolChar(243, draw), shift);
2040
	CurrentX = savedX;
2041
	CurrentY = savedY;
2042
	shift = TeX(sigma22) - 0.99 * bboxHeight(bbox2);
2043
	MoveUp(shift);
2044
	bbox2 = ShiftBBox(RenderSymbolChar(245, draw), shift);
2045
	if (draw)
2046
	    MoveTo(savedX + max(bboxWidth(bbox1), bboxWidth(bbox2)), savedY);
2047
	else
2048
	    MoveTo(savedX, savedY);
2049
	return CombineAlignedBBoxes(bbox1, bbox2);
2050
    }
2051
    else {
2052
	return RenderSymbolChar(0362, draw);
2053
    }
1926 ihaka 2054
}
2055
 
2028 ihaka 2056
static BBOX RenderInt(SEXP expr, int draw)
2 r 2057
{
2028 ihaka 2058
    BBOX opBBox, lowerBBox, upperBBox, bodyBBox;
2059
    int nexpr = length(expr);
2060
    STYLE style = GetStyle();
2061
    double savedX = CurrentX;
2062
    double savedY = CurrentY;
2063
    double hshift, vshift, width;
2 r 2064
 
2028 ihaka 2065
    opBBox = RenderIntSymbol(draw);
2066
    width = bboxWidth(opBBox);
2067
    CurrentX = savedX;
2068
    CurrentY = savedY;
2069
    if (nexpr > 2) {
2070
	hshift = 0.5 * width + ThinSpace();
2071
	SetSubStyle(style);
2072
	lowerBBox = RenderElement(CADDR(expr), 0);
2073
	vshift = bboxDepth(opBBox) + CenterShift(lowerBBox);
2074
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -vshift, draw);
2075
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
2076
	SetStyle(style);
2077
	CurrentX = savedX;
2078
	CurrentY = savedY;
1839 ihaka 2079
    }
2028 ihaka 2080
    if (nexpr > 3) {
2081
	hshift = width + ThinSpace();
2082
	SetSupStyle(style);
2083
	upperBBox = RenderElement(CADDDR(expr), 0);
2084
	vshift = bboxHeight(opBBox) - CenterShift(upperBBox);
2085
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, vshift, draw);
2086
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
2087
	SetStyle(style);
2088
	CurrentX = savedX;
2089
	CurrentY = savedY;
1839 ihaka 2090
    }
2028 ihaka 2091
    MoveAcross(bboxWidth(opBBox));
2092
    if (nexpr > 1) {
2093
	bodyBBox = RenderElement(CADR(expr), draw);
2094
	opBBox = CombineBBoxes(opBBox, bodyBBox);
1839 ihaka 2095
    }
2028 ihaka 2096
    return opBBox;
2 r 2097
}
2098
 
2099
 
2028 ihaka 2100
/*----------------------------------------------------------------------
2101
 *
2102
 *  Code for Operator Expressions (sum, product, lim, inf, sup, ...)
2103
 *
2104
 */
2 r 2105
 
2028 ihaka 2106
#define OperatorSymbolMag  1.25
2 r 2107
 
2028 ihaka 2108
static SymTab OpTable[] = {
2109
    "prod",          S_PRODUCT,
2110
    "sum",           S_SUM,
2111
    "union",         S_UNION,
2112
    "intersect",     S_INTERSECTION,
2113
    "lim",           N_LIM,
2114
    "liminf",        N_LIMINF,
2115
    "limsup",        N_LIMINF,
2116
    "inf",           N_INF,
2117
    "sup",           N_SUP,
2118
    "min",           N_MIN,
2119
    "max",           N_MAX,
2120
    NULL,            0
2121
};
2 r 2122
 
2028 ihaka 2123
static int OpAtom(SEXP expr)
2 r 2124
{
2028 ihaka 2125
    int i;
2126
    for (i = 0; OpTable[i].code; i++)
2127
	if (NameMatch(expr, OpTable[i].name))
2128
	    return OpTable[i].code;
2129
    return 0;
2 r 2130
}
2131
 
2028 ihaka 2132
static BBOX RenderOpSymbol(SEXP op, int draw)
2 r 2133
{
2028 ihaka 2134
    BBOX bbox;
2135
    double cexSaved = MathDevice->gp.cex;
2124 maechler 2136
    /*double savedX = CurrentX;*/
2137
    /*double savedY = CurrentY;*/
2028 ihaka 2138
    double shift;
2105 ihaka 2139
    int display = (GetStyle() > STYLE_T);
2028 ihaka 2140
    int opId = OpAtom(op);
2 r 2141
 
2028 ihaka 2142
    if (opId == S_SUM || opId == S_PRODUCT) {
2105 ihaka 2143
	if (display) {
2144
	    MathDevice->gp.cex = OperatorSymbolMag * MathDevice->gp.cex;
2145
	    bbox = RenderSymbolChar(OpAtom(op), 0);
2146
	    shift = 0.5 * (bboxHeight(bbox) - bboxDepth(bbox)) - TeX(sigma22);
2147
	    if (draw) {
2148
		MoveUp(-shift);
2149
		bbox = RenderSymbolChar(opId, 1);
2150
		MoveUp(shift);
2151
	    }
2152
	    MathDevice->gp.cex = cexSaved;
2153
	    return ShiftBBox(bbox, -shift);
2028 ihaka 2154
	}
2105 ihaka 2155
	else return RenderSymbolChar(opId, draw);
2028 ihaka 2156
    }
1839 ihaka 2157
    else {
2028 ihaka 2158
	FontType prevfont = SetFont(PlainFont);
2159
	bbox = RenderStr(CHAR(PRINTNAME(op)), draw);
2160
	SetFont(prevfont);
2161
	return bbox;
1839 ihaka 2162
    }
2 r 2163
}
2164
 
2028 ihaka 2165
static BBOX RenderOp(SEXP expr, int draw)
2 r 2166
{
2028 ihaka 2167
    BBOX lowerBBox, upperBBox, bodyBBox;
2168
    double savedX = CurrentX;
2169
    double savedY = CurrentY;
2170
    int nexpr = length(expr);
2171
    STYLE style = GetStyle();
2172
    BBOX opBBox = RenderOpSymbol(CAR(expr), 0);
2173
    double width = bboxWidth(opBBox);
2174
    double hshift, lvshift, uvshift;
2175
    if (nexpr > 2) {
2176
	SetSubStyle(style);
2177
	lowerBBox = RenderElement(CADDR(expr), 0);
2178
	SetStyle(style);
2179
	width = max(width, bboxWidth(lowerBBox));
2180
	lvshift = max(TeX(xi10), TeX(xi12) - bboxHeight(lowerBBox));
2181
	lvshift = bboxDepth(opBBox) + bboxHeight(lowerBBox) + lvshift;
2182
    }
2183
    if (nexpr > 3) {
2184
	SetSupStyle(style);
2185
	upperBBox = RenderElement(CADDDR(expr), 0);
2186
	SetStyle(style);
2187
	width = max(width, bboxWidth(upperBBox));
2188
	uvshift = max(TeX(xi9), TeX(xi11) - bboxDepth(upperBBox));
2189
	uvshift = bboxHeight(opBBox) + bboxDepth(upperBBox) + uvshift;
2190
    }
2191
    hshift = 0.5 * (width - bboxWidth(opBBox));
2192
    opBBox = RenderGap(hshift, draw);
2193
    opBBox = CombineBBoxes(opBBox, RenderOpSymbol(CAR(expr), draw));
2194
    CurrentX = savedX;
2195
    CurrentY = savedY;
2196
    if (nexpr > 2) {
2197
	SetSubStyle(style);
2198
	hshift = 0.5 * (width - bboxWidth(lowerBBox));
2199
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -lvshift, draw);
2200
	SetStyle(style);
2201
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
2202
	CurrentX = savedX;
2203
	CurrentY = savedY;
2204
    }
2205
    if (nexpr > 3) {
2206
	SetSupStyle(style);
2207
	hshift = 0.5 * (width - bboxWidth(upperBBox));
2208
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, uvshift, draw);
2209
	SetStyle(style);
2210
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
2211
	CurrentX = savedX;
2212
	CurrentY = savedY;
2213
    }
2214
    opBBox = EnlargeBBox(opBBox, TeX(xi13), TeX(xi13), 0);
2215
    if (draw)
2216
	MoveAcross(width);
2217
    opBBox = CombineBBoxes(opBBox, RenderGap(ThinSpace(), draw));
2218
    bodyBBox = RenderElement(CADR(expr), draw);
2219
    return CombineBBoxes(opBBox, bodyBBox);
2 r 2220
}
2221
 
2222
 
2028 ihaka 2223
/*----------------------------------------------------------------------
2224
 *
2225
 *  Code for radical expressions (root, sqrt)
2226
 *
2227
 *  Tunable parameteters :
2228
 *
2229
 *  RADICAL_GAP    The gap between the nucleus and the radical extension.
2230
 *  RADICAL_SPACE  Extra space to the left and right of the nucleus.
2231
 *
2232
 */
2 r 2233
 
2028 ihaka 2234
#define RADICAL_GAP    0.4
2235
#define RADICAL_SPACE  0.2
2 r 2236
 
2028 ihaka 2237
static int RadicalAtom(SEXP expr)
2 r 2238
{
2028 ihaka 2239
    return NameAtom(expr) &&
2240
	(NameMatch(expr, "root") ||
2241
	 NameMatch(expr, "sqrt"));
2 r 2242
}
2243
 
2028 ihaka 2244
static BBOX RenderScript(SEXP expr, int draw)
2 r 2245
{
2028 ihaka 2246
    BBOX bbox;
2247
    STYLE style = GetStyle();
2248
    SetSupStyle(style);
2249
    bbox = RenderElement(expr, draw);
2250
    SetStyle(style);
2251
    return bbox;
2 r 2252
}
2253
 
2028 ihaka 2254
static BBOX RenderRadical(SEXP expr, int draw)
2 r 2255
{
1839 ihaka 2256
    SEXP body = CADR(expr);
2028 ihaka 2257
    SEXP order = CADDR(expr);
2124 maechler 2258
    BBOX bodyBBox, orderBBox;
2028 ihaka 2259
    double radWidth, radHeight, radDepth;
2260
    double leadWidth, leadHeight, twiddleHeight;
2261
    double hshift, vshift;
2262
    double radGap, radSpace, radTrail;
2263
    STYLE style = GetStyle();
2264
    double savedX = CurrentX;
2265
    double savedY = CurrentY;
2266
    double x[5], y[5];
2 r 2267
 
2028 ihaka 2268
    radGap = RADICAL_GAP * xHeight();
2269
    radSpace = RADICAL_SPACE * xHeight();
2270
    radTrail = MuSpace();
2271
    SetPrimeStyle(style);
2272
    bodyBBox = RenderElement(body, 0);
2273
    bodyBBox = RenderItalicCorr(bodyBBox, 0);
2 r 2274
 
2028 ihaka 2275
    radWidth = 0.6 *XHeight();
2276
    radHeight = bboxHeight(bodyBBox) + radGap;
2277
    radDepth = bboxDepth(bodyBBox);
2278
    twiddleHeight = CenterShift(bodyBBox);
2 r 2279
 
2028 ihaka 2280
    leadWidth = radWidth;
2281
    leadHeight = radHeight;
2282
    if (order != R_NilValue) {
2283
	SetSupStyle(style);
2284
	orderBBox = RenderScript(order, 0);
2285
	leadWidth = max(leadWidth, bboxWidth(orderBBox) + 0.4 * radWidth);
2286
	hshift = leadWidth - bboxWidth(orderBBox) - 0.4 * radWidth;
2287
	vshift = leadHeight - bboxHeight(orderBBox);
2288
	if (vshift - bboxDepth(orderBBox) < twiddleHeight + radGap)
2289
	    vshift = twiddleHeight + bboxDepth(orderBBox) + radGap;
2290
	if (draw) {
2291
	    MoveTo(savedX + hshift, savedY + vshift);
2292
	    orderBBox = RenderScript(order, draw);
2293
	}
2294
	orderBBox = EnlargeBBox(orderBBox, vshift, 0, hshift);
1839 ihaka 2295
    }
2028 ihaka 2296
    else
2297
	orderBBox = NullBBox();
2298
    if (draw) {
2299
	MoveTo(savedX + leadWidth - radWidth, savedY);
2300
	MoveUp(0.8 * twiddleHeight);
2301
	x[0] = ConvertedX();
2302
	y[0] = ConvertedY();
2303
	MoveUp(0.2 * twiddleHeight);
2304
	MoveAcross(0.3 * radWidth);
2305
	x[1] = ConvertedX();
2306
	y[1] = ConvertedY();
2307
	MoveUp(-(twiddleHeight + bboxDepth(bodyBBox)));
2308
	MoveAcross(0.3 * radWidth);
2309
	x[2] = ConvertedX();
2310
	y[2] = ConvertedY();
2311
	MoveUp(bboxDepth(bodyBBox) + bboxHeight(bodyBBox) + radGap);
2312
	MoveAcross(0.4 * radWidth);
2313
	x[3] = ConvertedX();
2314
	y[3] = ConvertedY();
2315
	MoveAcross(radSpace + bboxWidth(bodyBBox) + radTrail);
2316
	x[4] = ConvertedX();
2317
	y[4] = ConvertedY();
2318
	GPolyline(5, x, y, INCHES, MathDevice);
2319
	MoveTo(savedX, savedY);
2320
    }
2321
    orderBBox = CombineAlignedBBoxes(orderBBox,
2322
				     RenderGap(leadWidth + radSpace, draw));
2323
    SetPrimeStyle(style);
2324
    orderBBox = CombineBBoxes(orderBBox, RenderElement(body, draw));
2325
    orderBBox = CombineBBoxes(orderBBox, RenderGap(2 * radTrail, draw));
2326
    SetStyle(style);
2327
    return orderBBox;
2 r 2328
}
2329
 
2028 ihaka 2330
/*----------------------------------------------------------------------
2331
 *
2332
 *  Code for Absolute Value Expressions (abs)
2333
 *
2334
 */
2 r 2335
 
2028 ihaka 2336
static int AbsAtom(SEXP expr)
2 r 2337
{
2028 ihaka 2338
    return NameAtom(expr) && NameMatch(expr, "abs");
2 r 2339
}
2340
 
2028 ihaka 2341
static BBOX RenderAbs(SEXP expr, int draw)
2 r 2342
{
2028 ihaka 2343
    BBOX bbox = RenderElement(CADR(expr), 0);
2344
    double height = bboxHeight(bbox);
2345
    double depth = bboxDepth(bbox);
1839 ihaka 2346
    double x[2], y[2];
2 r 2347
 
2028 ihaka 2348
    bbox= RenderGap(MuSpace(), draw);
2349
    if (draw) {
2350
	MoveUp(-depth);
2351
	x[0] = ConvertedX();
2352
	y[0] = ConvertedY();
2353
	MoveUp(depth + height);
2354
	x[1] = ConvertedX();
2355
	y[1] = ConvertedY();
2356
	GPolyline(2, x, y, INCHES, MathDevice);
2357
	MoveUp(-height);
2358
    }
2359
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(), draw));
2360
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw));
2361
    bbox = RenderItalicCorr(bbox, draw);
2362
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(), draw));
2363
    if (draw) {
2364
	MoveUp(-depth);
2365
	x[0] = ConvertedX();
2366
	y[0] = ConvertedY();
2367
	MoveUp(depth + height);
2368
	x[1] = ConvertedX();
2369
	y[1] = ConvertedY();
2370
	GPolyline(2, x, y, INCHES, MathDevice);
2371
	MoveUp(-height);
2372
    }
2373
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(), draw));
2374
    return bbox;
2 r 2375
}
2376
 
2028 ihaka 2377
/*----------------------------------------------------------------------
2378
 *
2379
 *  Code for Grouped Expressions (i.e. { ... } )
2380
 *
2381
 */
2 r 2382
 
2028 ihaka 2383
static int CurlyAtom(SEXP expr)
2 r 2384
{
2028 ihaka 2385
    return NameAtom(expr) &&
2386
	NameMatch(expr, "{");
2 r 2387
}
2388
 
2028 ihaka 2389
static BBOX RenderCurly(SEXP expr, int draw)
2 r 2390
{
2028 ihaka 2391
    return RenderElement(CADR(expr), draw);
2 r 2392
}
2393
 
2394
 
2028 ihaka 2395
/*----------------------------------------------------------------------
2396
 *
2397
 *  Code for Relation Expressions (i.e. ... ==, !=, ...)
2398
 *
2399
 */
2 r 2400
 
2028 ihaka 2401
                                /* Binary Relationships */
2 r 2402
 
2028 ihaka 2403
SymTab RelTable[] = {
2122 maechler 2404
    "<",                 60,    /* less */
2028 ihaka 2405
    "==",                61,    /* equal */
2406
    ">",                 62,    /* greater */
2407
    "%=~%",              64,    /* congruent */
2408
    "!=",               185,    /* not equal */
2409
    "<=",               163,    /* less or equal */
2410
    ">=",               179,    /* greater or equal */
2411
    "%==%",             186,    /* equivalence */
2412
    "%~~%",             187,    /* approxequal */
2 r 2413
 
2028 ihaka 2414
    "%<->%",            171,    /* Arrows */
2415
    "%<-%",             172,
2416
    "%up%",             173,
2417
    "%->%",             174,
2418
    "%down%",           175,
2419
    "%<=>%",            219,
2420
    "%<=%",             220,
2421
    "%dblup%",          221,
2422
    "%=>%",             222,
2423
    "%dbldown%",        223,
2 r 2424
 
2028 ihaka 2425
    "%supset%",         201,    /* Sets (TeX Names) */
2426
    "%supseteq%",       202,
2427
    "%notsubset%",      203,
2428
    "%subset%",         204,
2429
    "%subseteq%",       205,
2430
    "%in%",             206,
2431
    "%notin%",          207,
2 r 2432
 
2028 ihaka 2433
    NULL,                0,
2434
};
1016 maechler 2435
 
2028 ihaka 2436
static int RelAtom(SEXP expr)
2 r 2437
{
2028 ihaka 2438
    int i;
2439
    for (i = 0; RelTable[i].code; i++)
2440
	if (NameMatch(expr, RelTable[i].name))
2441
	    return RelTable[i].code;
2442
    return 0;
2 r 2443
}
2444
 
2028 ihaka 2445
static BBOX RenderRel(SEXP expr, int draw)
2 r 2446
{
2028 ihaka 2447
    int op = RelAtom(CAR(expr));
2448
    int nexpr = length(expr);
2449
    BBOX bbox;
2450
    double gap;
2 r 2451
 
2028 ihaka 2452
    if(nexpr == 3) {
2122 maechler 2453
	gap = (CurrentStyle > STYLE_S) ? ThickSpace() : 0;
2028 ihaka 2454
	bbox = RenderElement(CADR(expr), draw);
2455
	bbox = RenderItalicCorr(bbox, draw);
2456
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
2457
	bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw));
2458
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
2459
	return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw));
2 r 2460
    }
2028 ihaka 2461
    else error("invalid mathematical annotation\n");
2 r 2462
}
2463
 
1016 maechler 2464
 
2028 ihaka 2465
/*----------------------------------------------------------------------
2466
 *
2467
 *  Code for Boldface Expressions
2468
 *
2469
 */
2 r 2470
 
2028 ihaka 2471
static int BoldAtom(SEXP expr)
2 r 2472
{
2028 ihaka 2473
    return NameAtom(expr) &&
2474
	NameMatch(expr, "bold");
2 r 2475
}
2476
 
2028 ihaka 2477
static BBOX RenderBold(SEXP expr, int draw)
2 r 2478
{
2028 ihaka 2479
    BBOX bbox;
2480
    FontType prevfont = SetFont(BoldFont);
2481
    bbox = RenderElement(CADR(expr), draw);
2482
    SetFont(prevfont);
2483
    return bbox;
2 r 2484
}
2485
 
2028 ihaka 2486
/*----------------------------------------------------------------------
2487
 *
2488
 *  Code for Italic Expressions
2489
 *
2490
 */
2 r 2491
 
2028 ihaka 2492
static int ItalicAtom(SEXP expr)
2 r 2493
{
2028 ihaka 2494
    return NameAtom(expr) &&
2495
	(NameMatch(expr, "italic") || NameMatch(expr, "math"));
2 r 2496
}
2497
 
2028 ihaka 2498
static BBOX RenderItalic(SEXP expr, int draw)
2 r 2499
{
2028 ihaka 2500
    BBOX bbox;
2501
    FontType prevfont = SetFont(ItalicFont);
2502
    bbox = RenderElement(CADR(expr), draw);
2503
    SetFont(prevfont);
2504
    return bbox;
2 r 2505
}
2506
 
2028 ihaka 2507
/*----------------------------------------------------------------------
2508
 *
2509
 *  Code for Plain (i.e. Roman) Expressions
2510
 *
2511
 */
2 r 2512
 
2028 ihaka 2513
static int PlainAtom(SEXP expr)
2 r 2514
{
2028 ihaka 2515
    return NameAtom(expr) &&
2516
	NameMatch(expr, "plain");
2 r 2517
}
2518
 
2028 ihaka 2519
static BBOX RenderPlain(SEXP expr, int draw)
2 r 2520
{
2028 ihaka 2521
    BBOX bbox;
2522
    int prevfont = SetFont(PlainFont);
2523
    bbox = RenderElement(CADR(expr), draw);
2524
    SetFont(prevfont);
2525
    return bbox;
2 r 2526
}
2527
 
2028 ihaka 2528
/*----------------------------------------------------------------------
2529
 *
2530
 *  Code for Bold Italic Expressions
2531
 *
2532
 */
2 r 2533
 
2028 ihaka 2534
static int BoldItalicAtom(SEXP expr)
2 r 2535
{
2028 ihaka 2536
    return NameAtom(expr) &&
2537
	(NameMatch(expr, "bolditalic") || NameMatch(expr, "boldmath"));
2 r 2538
}
2539
 
2028 ihaka 2540
static BBOX RenderBoldItalic(SEXP expr, int draw)
2 r 2541
{
2028 ihaka 2542
    BBOX bbox;
2543
    int prevfont = SetFont(BoldItalicFont);
2544
    bbox = RenderElement(CADR(expr), draw);
2545
    SetFont(prevfont);
2546
    return bbox;
2 r 2547
}
2548
 
2028 ihaka 2549
/*----------------------------------------------------------------------
2550
 *
2551
 *  Code for Styles
2552
 *
2553
 */
2 r 2554
 
2028 ihaka 2555
static int StyleAtom(SEXP expr)
2 r 2556
{
2028 ihaka 2557
    return (NameAtom(expr) &&
2558
	    (NameMatch(expr, "displaystyle") ||
2559
	     NameMatch(expr, "textstyle")    ||
2560
	     NameMatch(expr, "scriptstyle")   ||
2561
	     NameMatch(expr, "scriptscriptstyle")));
2 r 2562
}
2563
 
2028 ihaka 2564
static BBOX RenderStyle(SEXP expr, int draw)
2 r 2565
{
2028 ihaka 2566
    STYLE prevstyle = GetStyle();
2567
    BBOX bbox;
2122 maechler 2568
    if (NameMatch(CAR(expr), "displaystyle"))
2028 ihaka 2569
	SetStyle(STYLE_D);
2122 maechler 2570
    else if (NameMatch(CAR(expr), "textstyle"))
2028 ihaka 2571
	SetStyle(STYLE_T);
2122 maechler 2572
    else if (NameMatch(CAR(expr), "scriptstyle"))
2028 ihaka 2573
	SetStyle(STYLE_S);
2122 maechler 2574
    else if (NameMatch(CAR(expr), "scriptscriptstyle"))
2028 ihaka 2575
	SetStyle(STYLE_SS);
2576
    bbox = RenderElement(CADR(expr), draw);
2577
    SetStyle(prevstyle);
2578
    return bbox;
2 r 2579
}
2580
 
2028 ihaka 2581
/*----------------------------------------------------------------------
2582
 *
2583
 *  Code for Phantom Expressions
2584
 *
2585
 */
2 r 2586
 
2028 ihaka 2587
static int PhantomAtom(SEXP expr)
2 r 2588
{
2028 ihaka 2589
    return (NameAtom(expr) &&
2590
	    (NameMatch(expr, "phantom") ||
2591
	     NameMatch(expr, "vphantom")));
2 r 2592
}
2593
 
2028 ihaka 2594
static BBOX RenderPhantom(SEXP expr, int draw)
2 r 2595
{
2028 ihaka 2596
    BBOX bbox = RenderElement(CADR(expr), 0);
2597
    if (NameMatch(CAR(expr), "vphantom")) {
2598
	bboxWidth(bbox) = 0;
2599
	bboxItalic(bbox) = 0;
2600
    }
2601
    else RenderGap(bboxWidth(bbox), 0);
2602
    return bbox;
2 r 2603
}
2604
 
2028 ihaka 2605
/*----------------------------------------------------------------------
2606
 *
2607
 *  Code for Concatenate Expressions
2608
 *
2609
 */
2 r 2610
 
2028 ihaka 2611
static int ConcatenateAtom(SEXP expr)
2 r 2612
{
2028 ihaka 2613
    return NameAtom(expr) && NameMatch(expr, "paste");
2 r 2614
}
2615
 
2028 ihaka 2616
static BBOX RenderConcatenate(SEXP expr, int draw)
2 r 2617
{
2028 ihaka 2618
    BBOX bbox;
2619
    int i, n;
2 r 2620
 
2028 ihaka 2621
    expr = CDR(expr);
2622
    n = length(expr);
2 r 2623
 
2028 ihaka 2624
    for (i = 0; i < n; i++) {
2625
	bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw));
2626
	if (i != n - 1)
2627
	    bbox = RenderItalicCorr(bbox, draw);
2628
	expr = CDR(expr);
2629
    }
2630
    return bbox;
2 r 2631
}
2632
 
2028 ihaka 2633
/*----------------------------------------------------------------------
2634
 *
2635
 *  Code for Comma-Separated Lists
2636
 *
2637
 */
2 r 2638
 
2028 ihaka 2639
static BBOX RenderCommaList(SEXP expr, int draw)
2 r 2640
{
2028 ihaka 2641
    BBOX bbox = NullBBox();
2642
    double small = 0.4 * ThinSpace();
2643
    int i, n;
2644
    n = length(expr);
2645
    for (i = 0; i < n; i++) {
2646
	if (NameAtom(CAR(expr)) && NameMatch(CAR(expr), "...")) {
2647
	    if (i > 0) {
2648
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw));
2649
#ifdef OLD
2650
		bbox = CombineBBoxes(bbox, RenderGap(small, draw));
2651
#else
2652
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw));
2653
#endif
2654
	    }
2655
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(S_ELLIPSIS, draw));
2656
	    bbox = CombineBBoxes(bbox, RenderGap(small, draw));
2657
	}
2658
	else {
2659
	    if (i > 0) {
2660
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw));
2661
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw));
2662
	    }
2663
	    bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw));
2664
	}
2665
	expr = CDR(expr);
2666
    }
2667
    return bbox;
2 r 2668
}
2669
 
2028 ihaka 2670
/*----------------------------------------------------------------------
2671
 *
2672
 *  Code for General Expressions
2673
 *
2674
 */
2 r 2675
 
2028 ihaka 2676
static BBOX RenderExpression(SEXP expr, int draw)
2 r 2677
{
2028 ihaka 2678
    BBOX bbox;
2679
    if (NameAtom(CAR(expr)))
2680
	bbox = RenderSymbolString(CAR(expr), draw);
2681
    else
2682
	bbox = RenderElement(CAR(expr), draw);
2683
    bbox = RenderItalicCorr(bbox, draw);
2105 ihaka 2684
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENLEFT, draw));
2028 ihaka 2685
    bbox = CombineBBoxes(bbox, RenderCommaList(CDR(expr), draw));
2686
    bbox = RenderItalicCorr(bbox, draw);
2105 ihaka 2687
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw));
2028 ihaka 2688
    return bbox;
2 r 2689
}
2690
 
2028 ihaka 2691
/*----------------------------------------------------------------------
2692
 *
2693
 *  Code for Comma Separated List Expressions
2694
 *
2695
 */
2 r 2696
 
2028 ihaka 2697
static int ListAtom(SEXP expr)
2 r 2698
{
2028 ihaka 2699
    return NameAtom(expr) && NameMatch(expr, "list");
2 r 2700
}
2701
 
2028 ihaka 2702
static BBOX RenderList(SEXP expr, int draw)
2 r 2703
{
2028 ihaka 2704
    return RenderCommaList(CDR(expr), draw);
2 r 2705
}
2706
 
1839 ihaka 2707
/* Dispatching procedure which determines nature of expression. */
2 r 2708
 
2028 ihaka 2709
 
2710
static BBOX RenderFormula(SEXP expr, int draw)
2 r 2711
{
1839 ihaka 2712
    SEXP head = CAR(expr);
2 r 2713
 
2028 ihaka 2714
    if (SpaceAtom(head))
2715
	return RenderSpace(expr, draw);
2716
    else if (BinAtom(head))
2717
	return RenderBin(expr, draw);
2718
    else if (SuperAtom(head))
2719
	return RenderSup(expr, draw);
2720
    else if (SubAtom(head))
2721
	return RenderSub(expr, draw);
2722
    else if (WideTildeAtom(head))
2723
	return RenderWideTilde(expr, draw);
2724
    else if (WideHatAtom(head))
2725
	return RenderWideHat(expr, draw);
2726
    else if (BarAtom(head))
2727
	return RenderBar(expr, draw);
2728
    else if (AccentAtom(head))
2729
	return RenderAccent(expr, draw);
2730
    else if (OverAtom(head))
2731
	return RenderOver(expr, draw);
2732
    else if (AtopAtom(head))
2733
	return RenderAtop(expr, draw);
2734
    else if (ParenAtom(head))
2735
	return RenderParen(expr, draw);
2736
    else if (BGroupAtom(head))
2737
	return RenderBGroup(expr, draw);
2738
    else if (GroupAtom(head))
2739
	return RenderGroup(expr, draw);
2740
    else if (IntAtom(head))
2741
       	return RenderInt(expr, draw);
2742
    else if (OpAtom(head))
2743
	return RenderOp(expr, draw);
2744
    else if (RadicalAtom(head))
2745
	return RenderRadical(expr, draw);
2746
    else if (AbsAtom(head))
2747
	return RenderAbs(expr, draw);
2748
    else if (CurlyAtom(head))
2749
	return RenderCurly(expr, draw);
2750
    else if (RelAtom(head))
2751
	return RenderRel(expr, draw);
2752
    else if (BoldAtom(head))
2753
	return RenderBold(expr, draw);
2754
    else if (ItalicAtom(head))
2755
	return RenderItalic(expr, draw);
2756
    else if (PlainAtom(head))
2757
	return RenderPlain(expr, draw);
2758
    else if (BoldItalicAtom(head))
2759
	return RenderBoldItalic(expr, draw);
2760
    else if (StyleAtom(head))
2761
	return RenderStyle(expr, draw);
2762
    else if (PhantomAtom(head))
2763
	return RenderPhantom(expr, draw);
2764
    else if (ConcatenateAtom(head))
2765
	return RenderConcatenate(expr, draw);
2766
    else if (ListAtom(head))
2767
	return RenderList(expr, draw);
1839 ihaka 2768
    else
2028 ihaka 2769
	return RenderExpression(expr, draw);
2 r 2770
}
2771
 
2772
 
2028 ihaka 2773
/* Dispatch on whether atom (symbol, string, number, ...) */
2774
/* or formula (some sort of expression) */
2 r 2775
 
2028 ihaka 2776
static BBOX RenderElement(SEXP expr, int draw)
2777
{
2778
    if (FormulaExpression(expr))
2779
	return RenderFormula(expr, draw);
1839 ihaka 2780
    else
2028 ihaka 2781
	return RenderAtom(expr, draw);
2 r 2782
}
2783
 
2028 ihaka 2784
static BBOX RenderOffsetElement(SEXP expr, double x, double y, int draw)
2785
{
2786
    BBOX bbox;
2787
    double savedX = CurrentX;
2788
    double savedY = CurrentY;
2789
    if (draw) {
2790
	CurrentX += x;
2791
	CurrentY += y;
2792
    }
2793
    bbox = RenderElement(expr, draw);
2794
    bboxWidth(bbox) += x;
2795
    bboxHeight(bbox) += y;
2796
    bboxDepth(bbox) -= y;
2797
    CurrentX = savedX;
2798
    CurrentY = savedY;
2799
    return bbox;
2 r 2800
 
2801
}
2802
 
2028 ihaka 2803
/* Calculate width of expression */
2804
/* BBOXes are in INCHES (see MetricUnit) */
2805
 
2806
void GExpressionBBox(SEXP expr, int units, double *width,
2807
		     double *height, double *depth, DevDesc *dd)
2 r 2808
{
2028 ihaka 2809
    BBOX bbox = RenderElement(expr, 0);
2810
    *width  = bboxWidth(bbox);
2811
    *height  = bboxHeight(bbox);
2812
    *depth  = bboxDepth(bbox);
2813
    if (units != INCHES) {
2814
	*width = GConvertXUnits(*width, INCHES, units, dd);
2815
	*height = GConvertYUnits(*height, INCHES, units, dd);
2816
	*depth = GConvertYUnits(*depth, INCHES, units, dd);
2817
    }
2 r 2818
}
2819
 
581 paul 2820
double GExpressionWidth(SEXP expr, int units, DevDesc *dd)
257 paul 2821
{
2028 ihaka 2822
    BBOX bbox = RenderElement(expr, 0);
2823
    double width  = bboxWidth(bbox);
1839 ihaka 2824
    if (units == INCHES)
2028 ihaka 2825
	return width;
1839 ihaka 2826
    else
2028 ihaka 2827
	return GConvertXUnits(width, INCHES, units, dd);
257 paul 2828
}
2829
 
581 paul 2830
double GExpressionHeight(SEXP expr, int units, DevDesc *dd)
257 paul 2831
{
2028 ihaka 2832
    BBOX bbox = RenderElement(expr, 0);
2833
    double height = bboxHeight(bbox) + bboxDepth(bbox);
1839 ihaka 2834
    if (units == INCHES)
2028 ihaka 2835
	return height;
1839 ihaka 2836
    else
2028 ihaka 2837
	return GConvertYUnits(height, INCHES, units, dd);
257 paul 2838
}
2839
 
2028 ihaka 2840
/* Functions forming the R API */
2 r 2841
 
1016 maechler 2842
void GMathText(double x, double y, int coords, SEXP expr,
581 paul 2843
	       double xc, double yc, double rot, DevDesc *dd)
2 r 2844
{
2028 ihaka 2845
    BBOX bbox;
2846
    MathDevice = dd;
2847
    BaseCex = MathDevice->gp.cex;
2848
    BoxColor = name2col("pink");
2849
    TextColor = MathDevice->gp.col;
2850
    CurrentStyle = STYLE_D;
2105 ihaka 2851
    SetFont(PlainFont);
2028 ihaka 2852
    bbox = RenderElement(expr, 0);
2853
    ReferenceX = x;
2854
    ReferenceY = y;
2855
    GConvert(&ReferenceX, &ReferenceY, coords, INCHES, dd);
2856
    if (FINITE(xc))
2857
	CurrentX = ReferenceX - xc * bboxWidth(bbox);
2858
    else
2859
	CurrentX = ReferenceX;
2860
    if (FINITE(yc))
2861
	CurrentY = ReferenceY + bboxDepth(bbox)
2862
	    - yc * (bboxHeight(bbox) + bboxDepth(bbox));
2863
    else
2864
	CurrentY = ReferenceY;
2865
    CurrentAngle = rot;
2123 maechler 2866
    rot *= M_PI_half / 90 ;/* radians */
2122 maechler 2867
    CosAngle = cos(rot);
2868
    SinAngle = sin(rot);
2028 ihaka 2869
    RenderElement(expr, 1);
2 r 2870
}
2871
 
2872
 
2028 ihaka 2873
void GMMathText(SEXP str, int side, double line, int outer,
2874
		double at, int las, DevDesc *dd)
2 r 2875
{
1839 ihaka 2876
    int coords;
2877
    double a, xadj, yadj;
2 r 2878
 
2028 ihaka 2879
    MathDevice = dd;
581 paul 2880
 
1839 ihaka 2881
    if (outer) {
2882
	switch (side) {
2883
	case 1:
2884
	    line = line + 1;
2885
	    coords = MAR1;
2028 ihaka 2886
	    a = 0;
2887
	    xadj = MathDevice->gp.adj;
2888
	    yadj = NA_REAL;
1839 ihaka 2889
	    break;
2890
	case 2:
2891
	    coords = MAR2;
2028 ihaka 2892
	    a = 90;
2893
	    xadj = MathDevice->gp.adj;
2894
	    yadj = NA_REAL;
1839 ihaka 2895
	    break;
2896
	case 3:
2897
	    coords = MAR3;
2898
	    a = 0.0;
2028 ihaka 2899
	    xadj = MathDevice->gp.adj;
2900
	    yadj = NA_REAL;
1839 ihaka 2901
	    break;
2902
	case 4:
2903
	    line = line + 1;
2904
	    coords = MAR4;
2905
	    a = 90.0;
2028 ihaka 2906
	    xadj = MathDevice->gp.adj;
2907
	    yadj = NA_REAL;
1839 ihaka 2908
	    break;
2 r 2909
	}
1839 ihaka 2910
	GMathText(at, line, coords, str, xadj, yadj, a, dd);
2911
    }
2912
    else {
2913
	switch (side) {
2914
	case 1:
2915
	    if (las == 2) {
2916
		at = at - GConvertXUnits(dd->gp.yLineBias,
2917
					 LINES, USER, dd);
2918
		line = line + dd->gp.yLineBias;
2919
		a = 90.0;
2920
		xadj = 1.0;
2921
		yadj = 0.5;
2922
	    }
2923
	    else {
2924
		line = line + 1 - dd->gp.yLineBias;
2925
		a = 0.0;
2028 ihaka 2926
		xadj = MathDevice->gp.adj;
2927
		yadj = NA_REAL;
1839 ihaka 2928
	    }
2929
	    coords = MAR1;
2930
	    break;
2931
	case 2:
2932
	    if (las == 1 || las == 2) {
2933
		at = at + GConvertYUnits(dd->gp.yLineBias,
2934
					 LINES, USER, dd);
2935
		line = line + dd->gp.yLineBias;
2936
		a = 0.0;
2937
		xadj = 1.0;
2938
		yadj = 0.5;
2939
	    }
2940
	    else {
2941
		line = line + dd->gp.yLineBias;
2942
		a = 90.0;
2028 ihaka 2943
		xadj = MathDevice->gp.adj;
2944
		yadj = NA_REAL;
1839 ihaka 2945
	    }
2946
	    coords = MAR2;
2947
	    break;
2948
	case 3:
2949
	    if (las == 2) {
2950
		at = at - GConvertXUnits(dd->gp.yLineBias,
2951
					 LINES, USER, dd);
2952
		line = line + dd->gp.yLineBias;
2953
		a = 90.0;
2954
		xadj = 0.0;
2955
		yadj = 0.5;
2956
	    }
2957
	    else {
2958
		line = line + dd->gp.yLineBias;
2959
		a = 0.0;
2028 ihaka 2960
		xadj = MathDevice->gp.adj;
2961
		yadj = NA_REAL;
1839 ihaka 2962
	    }
2963
	    coords = MAR3;
2964
	    break;
2965
	case 4:
2966
	    if (las == 1 || las == 2) {
2967
		at = at + GConvertYUnits(dd->gp.yLineBias,
2968
					 LINES, USER, dd);
2969
		line = line + dd->gp.yLineBias;
2970
		a = 0.0;
2971
		xadj = 0.0;
2972
		yadj = 0.5;
2973
	    }
2974
	    else {
2975
		line = line + 1 - dd->gp.yLineBias;
2976
		a = 90.0;
2028 ihaka 2977
		xadj = MathDevice->gp.adj;
2978
		yadj = NA_REAL;
1839 ihaka 2979
	    }
2980
	    coords = MAR4;
2981
	    break;
2 r 2982
	}
1839 ihaka 2983
	GMathText(at, line, coords, str, xadj, yadj, a, dd);
2984
    }
2 r 2985
}