The R Project SVN R

Rev

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