The R Project SVN R

Rev

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