The R Project SVN R

Rev

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