The R Project SVN R

Rev

Rev 3244 | Rev 3786 | 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[] = {
3475 pd 647
    "space",	      32,
648
    "exclam",	      33,
2028 ihaka 649
    "universal",      34,
650
    "numbersign",     35,
651
    "existential",    36,
3475 pd 652
    "percent",	      37,
2028 ihaka 653
    "ampersand",      38,
3475 pd 654
    "suchthat",	      39,
2028 ihaka 655
    "parenleft",      40,
656
    "parenright",     41,
657
    "asteriskmath",   42,
3475 pd 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,
2028 ihaka 674
    "semicolon",      59,
3475 pd 675
    "less",	      60,
676
    "equal",	      61,
677
    "greater",	      62,
678
    "question",	      63,
2028 ihaka 679
    "congruent",      64,
680
 
3475 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
 
2028 ihaka 708
    "bracketleft",    91,    /* Miscellaneous Special Characters */
709
    "therefore",      92,
710
    "bracketright",   93,
711
    "perpendicular",  94,
712
    "underscore",     95,
713
    "radicalex",      96,
714
 
3475 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
 
2028 ihaka 742
    "braceleft",     123,    /* Miscellaneous Special Characters */
3475 pd 743
    "bar",	     124,
2028 ihaka 744
    "braceright",    125,
3475 pd 745
    "similar",	     126,
2028 ihaka 746
 
3475 pd 747
    "Upsilon1",	     161,    /* Lone Greek */
748
    "minute",	     162,
2028 ihaka 749
    "lessequal",     163,
3475 pd 750
    "fraction",	     164,
751
    "infinity",	     165,
752
    "florin",	     166,
753
    "club",	     167,
754
    "diamond",	     168,
755
    "heart",	     169,
756
    "spade",	     170,
2028 ihaka 757
    "arrowboth",     171,
758
    "arrowleft",     172,
3475 pd 759
    "arrowup",	     173,
2028 ihaka 760
    "arrowright",    174,
761
    "arrowdown",     175,
3475 pd 762
    "degree",	     176,
2028 ihaka 763
    "plusminus",     177,
3475 pd 764
    "second",	     178,
2028 ihaka 765
    "greaterequal",  179,
3475 pd 766
    "multiply",	     180,
2028 ihaka 767
    "proportional",  181,
1926 ihaka 768
    "partialdiff",   182,
3475 pd 769
    "bullet",	     183,
770
    "divide",	     184,
771
    "notequal",	     185,
2028 ihaka 772
    "equivalence",   186,
773
    "approxequal",   187,
3475 pd 774
    "ellipsis",	     188,
2028 ihaka 775
    "arrowvertex",   189,
776
    "arrowhorizex",  190,
777
    "carriagereturn",191,
3475 pd 778
    "aleph",	     192,
779
    "Ifraktur",	     193,
780
    "Rfraktur",	     194,
1926 ihaka 781
    "weierstrass",   195,
2028 ihaka 782
    "circlemultiply",196,
783
    "circleplus",    197,
3475 pd 784
    "emptyset",	     198,
2028 ihaka 785
    "intersection",  199,
3475 pd 786
    "union",	     200,
2028 ihaka 787
    "propersuperset",201,
788
    "reflexsuperset",202,
789
    "notsubset",     203,
790
    "propersubset",  204,
791
    "reflexsubset",  205,
3475 pd 792
    "element",	     206,
2028 ihaka 793
    "notelement",    207,
3475 pd 794
    "angle",	     208,
795
    "gradient",	     209,
2028 ihaka 796
    "registerserif", 210,
797
    "copyrightserif",211,
798
    "trademarkserif",212,
3475 pd 799
    "product",	     213,
800
    "radical",	     214,
801
    "dotmath",	     215,
2028 ihaka 802
    "logicaland",    217,
803
    "logicalor",     218,
804
    "arrowdblboth",  219,
805
    "arrowdblleft",  220,
806
    "arrowdblup",    221,
807
    "arrowdblright", 222,
808
    "arrowdbldown",  223,
3475 pd 809
    "lozenge",	     224,
2028 ihaka 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,
3475 pd 824
    "braceex",	     239,
2028 ihaka 825
    "angleright",    241,
3475 pd 826
    "integral",	     242,
2028 ihaka 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
 
3475 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);
2 r 1168
}
1169
 
1170
 
2028 ihaka 1171
/*----------------------------------------------------------------------
1172
 *
1173
 *  Code for Binary / Unary Operators  (~, +, -, ... )
1174
 *
1175
 *  Note that there are unary and binary ~ s.
1176
 *
1177
 */
2 r 1178
 
2028 ihaka 1179
static int SpaceAtom(SEXP expr)
2 r 1180
{
2028 ihaka 1181
    return NameAtom(expr) && NameMatch(expr, "~");
2 r 1182
}
1183
 
1184
 
2028 ihaka 1185
static BBOX RenderSpace(SEXP expr, int draw)
2 r 1186
{
2124 maechler 1187
 
2028 ihaka 1188
    BBOX opBBox, arg1BBox, arg2BBox;
1189
    int nexpr = length(expr);
2 r 1190
 
2028 ihaka 1191
    if (nexpr == 2) {
1192
	opBBox = RenderSymbolChar(' ', draw);
1193
	arg1BBox = RenderElement(CADR(expr), draw);
1194
	return CombineBBoxes(opBBox, arg1BBox);
1195
    }
1196
    else if (nexpr == 3) {
1197
	arg1BBox = RenderElement(CADR(expr), draw);
1198
	opBBox = RenderSymbolChar(' ', draw);
1199
	arg2BBox = RenderElement(CADDR(expr), draw);
1200
	opBBox = CombineBBoxes(arg1BBox, opBBox);
1201
	opBBox = CombineBBoxes(opBBox, arg2BBox);
1202
	return opBBox;
1203
    }
1839 ihaka 1204
    else
2028 ihaka 1205
	error("invalid mathematical annotation\n");
2 r 1206
}
1207
 
2028 ihaka 1208
static SymTab BinTable[] = {
3475 pd 1209
    "*",		052,	/* Binary Operators */
1210
    "+",		053,
1211
    "-",		055,
1212
    "/",		057,
1213
    ":",		072,
1214
    "%+-%",	       0261,
1215
    "%*%",	       0264,
1216
    "%/%",	       0270,
2105 ihaka 1217
    "%intersection%",  0307,
3475 pd 1218
    "%union%",	       0310,
1219
    NULL,		  0
2028 ihaka 1220
};
2 r 1221
 
2028 ihaka 1222
static int BinAtom(SEXP expr)
2 r 1223
{
2028 ihaka 1224
    int i;
1225
    for (i = 0; BinTable[i].code; i++)
1226
	if (NameMatch(expr, BinTable[i].name))
1227
	    return BinTable[i].code;
1228
    return 0;
2 r 1229
}
1230
 
2028 ihaka 1231
#define SLASH2
2 r 1232
 
2028 ihaka 1233
static BBOX RenderSlash(int draw)
2 r 1234
{
2028 ihaka 1235
#ifdef SLASH0
1236
    /* The Default Font Character */
1237
    return RenderSymbolChar(S_SLASH, draw);
2 r 1238
#endif
2028 ihaka 1239
#ifdef SLASH1
1240
    /* Symbol Magnify Version */
1241
    double savecex = MathDevice->gp.cex;
1242
    BBOX bbox;
1243
    double height1, height2;
1244
    height1 = bboxHeight(RenderSymbolChar(S_SLASH, 0));
1245
    MathDevice->gp.cex = 1.2 * MathDevice->gp.cex;
1246
    height2 = bboxHeight(RenderSymbolChar(S_SLASH, 0));
1247
    if (draw)
3244 ihaka 1248
	PMoveUp(- 0.5 * (height2 - height1));
2028 ihaka 1249
    bbox = RenderSymbolChar(S_SLASH, draw);
1250
    if (draw)
3244 ihaka 1251
	PMoveUp(0.5 * (height2 - height1));
2028 ihaka 1252
    MathDevice->gp.cex = savecex;
1253
    return bbox;
2 r 1254
#endif
2028 ihaka 1255
#ifdef SLASH2
1256
    /* Line Drawing Version */
1257
    double x[2], y[2];
1258
    double depth = 0.5 * TeX(sigma22);
1259
    double height = XHeight() + 0.5 * TeX(sigma22);
1260
    double width = 0.5 * xHeight();
1261
    if (draw) {
3244 ihaka 1262
	PMoveAcross(0.5 * width);
1263
	PMoveUp(-depth);
2028 ihaka 1264
	x[0] = ConvertedX();
1265
	y[0] = ConvertedY();
3244 ihaka 1266
	PMoveAcross(width);
1267
	PMoveUp(depth + height);
2028 ihaka 1268
	x[1] = ConvertedX();
1269
	y[1] = ConvertedY();
3244 ihaka 1270
	PMoveUp(-height);
2028 ihaka 1271
	GPolyline(2, x, y, INCHES, MathDevice);
3244 ihaka 1272
	PMoveAcross(0.5 * width);
2028 ihaka 1273
    }
1274
    return MakeBBox(height, depth, 2 * width);
2 r 1275
#endif
2028 ihaka 1276
#ifdef SLASH3
1277
    /* Offset Overprinting - A Failure! */
1278
    BBOX slashBBox = RenderSymbolChar(S_SLASH, 0);
1279
    BBOX ansBBox;
1280
    double height = bboxHeight(slashBBox);
1281
    double depth = bboxDepth(slashBBox);
1282
    double width = bboxWidth(slashBBox);
1283
    double slope = (height + depth) / slope;
1284
    double delta = TeX(sigma22);
1285
    if (draw)
3244 ihaka 1286
	PMoveUp(-delta);
2028 ihaka 1287
    ansBBox = ShiftBBox(RenderSymbolChar(S_SLASH, draw), -delta);
3244 ihaka 1288
    PMoveUp(2 * delta);
2028 ihaka 1289
    ansBBox = CombineBBoxes(ansBBox, RenderGap(2 * delta / slope, draw));
1290
    ansBBox = ShiftBBox(RenderSymbolChar(S_SLASH, draw), 2 * delta);
3244 ihaka 1291
    PMoveUp(-delta);
2028 ihaka 1292
    return ansBBox;
2 r 1293
#endif
1294
}
1295
 
2028 ihaka 1296
static BBOX RenderBin(SEXP expr, int draw)
2 r 1297
{
2028 ihaka 1298
    int op = BinAtom(CAR(expr));
1299
    int nexpr = length(expr);
1300
    BBOX bbox;
1301
    double gap;
2 r 1302
 
2028 ihaka 1303
    if(nexpr == 3) {
1304
	if (op == S_ASTERISKMATH) {
1305
	    bbox = RenderElement(CADR(expr), draw);
1306
	    bbox = RenderItalicCorr(bbox, draw);
1307
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw));
1308
	}
1309
	else if (op == S_SLASH) {
1310
	    gap = 0;
1311
	    bbox = RenderElement(CADR(expr), draw);
1312
	    bbox = RenderItalicCorr(bbox, draw);
1313
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
1314
	    bbox = CombineBBoxes(bbox, RenderSlash(draw));
1315
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
1316
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw));
1317
	}
1318
	else {
2122 maechler 1319
	    gap = (CurrentStyle > STYLE_S) ? MediumSpace() : 0;
2028 ihaka 1320
	    bbox = RenderElement(CADR(expr), draw);
1321
	    bbox = RenderItalicCorr(bbox, draw);
1322
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
1323
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw));
1324
	    bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
1325
	    return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw));
1326
	}
1839 ihaka 1327
    }
2028 ihaka 1328
    else if(nexpr == 2) {
1329
	gap = (CurrentStyle > STYLE_S) ? ThinSpace() : 0;
1330
	bbox = RenderSymbolChar(op, draw);
1331
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
1332
	return CombineBBoxes(bbox, RenderElement(CADR(expr), draw));
1839 ihaka 1333
    }
2028 ihaka 1334
    else error("invalid mathematical annotation\n");
2 r 1335
}
1336
 
1337
 
2028 ihaka 1338
/*----------------------------------------------------------------------
1339
 *
1340
 *  Code for Subscript and Superscipt Expressions
1341
 *
1342
 *  Rules 18, 18a, ..., 18f of the TeXBook.
1343
 *
1344
 */
2 r 1345
 
2028 ihaka 1346
static int SuperAtom(SEXP expr)
2 r 1347
{
2028 ihaka 1348
    return NameAtom(expr) && NameMatch(expr, "^");
2 r 1349
}
1350
 
2028 ihaka 1351
static int SubAtom(SEXP expr)
2 r 1352
{
2028 ihaka 1353
    return NameAtom(expr) && NameMatch(expr, "[");
2 r 1354
}
1355
 
2028 ihaka 1356
/* Note : If all computations are correct */
1357
/* We do not need to save and restore the */
1358
/* current location here.  This is paranoia. */
1359
static BBOX RenderSub(SEXP expr, int draw)
2 r 1360
{
2028 ihaka 1361
    BBOX bodyBBox, subBBox;
1362
    SEXP body = CADR(expr);
1363
    SEXP sub = CADDR(expr);
1364
    STYLE style = GetStyle();
1365
    double savedX = CurrentX;
1366
    double savedY = CurrentY;
2124 maechler 1367
    double v, s5, s16;
2028 ihaka 1368
    bodyBBox = RenderElement(body, draw);
1369
    bodyBBox = RenderItalicCorr(bodyBBox, draw);
1370
    v = bboxSimple(bodyBBox) ? 0 : bboxDepth(bodyBBox) + TeX(sigma19);
1371
    s5 = TeX(sigma5);
1372
    s16 = TeX(sigma16);
1373
    SetSubStyle(style);
1374
    subBBox = RenderElement(sub, 0);
1375
    v = max(max(v, s16), bboxHeight(subBBox) - 0.8 * sigma5);
1376
    subBBox = RenderOffsetElement(sub, 0, -v, draw);
1377
    bodyBBox = CombineBBoxes(bodyBBox, subBBox);
1378
    SetStyle(style);
1379
    if (draw)
3244 ihaka 1380
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY);
2028 ihaka 1381
    return bodyBBox;
2 r 1382
}
1383
 
2028 ihaka 1384
static BBOX RenderSup(SEXP expr, int draw)
2 r 1385
{
2028 ihaka 1386
    BBOX bodyBBox, subBBox, supBBox;
1387
    SEXP body = CADR(expr);
1388
    SEXP sup = CADDR(expr);
1389
    SEXP sub;
1390
    STYLE style = GetStyle();
1391
    double savedX = CurrentX;
1392
    double savedY = CurrentY;
1393
    double theta, delta, width;
1394
    double u, p;
1395
    double v, s5, s17;
1396
    int haveSub;
1397
    if (FormulaExpression(body) && SubAtom(CAR(body))) {
1398
	sub = CADDR(body);
1399
	body = CADR(body);
1400
	haveSub = 1;
1401
    }
1402
    else haveSub = 0;
1403
    bodyBBox = RenderElement(body, draw);
1404
    delta = bboxItalic(bodyBBox);
1405
    bodyBBox = RenderItalicCorr(bodyBBox, draw);
1406
    width = bboxWidth(bodyBBox);
1407
    if (bboxSimple(bodyBBox)) {
1408
	u = 0;
1409
	v = 0;
1410
    }
1411
    else {
1412
	u = bboxHeight(bodyBBox) - TeX(sigma18);
1413
	v = bboxDepth(bodyBBox) + TeX(sigma19);
1414
    }
1415
    theta = TeX(xi8);
1416
    s5 = TeX(sigma5);
1417
    s17 = TeX(sigma17);
1418
    if (style == STYLE_D)
1419
	p = TeX(sigma13);
1420
    else if (IsCompactStyle(style))
1421
	p = TeX(sigma15);
1839 ihaka 1422
    else
2028 ihaka 1423
	p = TeX(sigma14);
1424
    SetSupStyle(style);
1425
    supBBox = RenderElement(sup, 0);
1426
    u = max(max(u, p), bboxDepth(supBBox) + 0.25 * s5);
2 r 1427
 
2028 ihaka 1428
    if (haveSub) {
1429
	SetSubStyle(style);
1430
	subBBox = RenderElement(sub, 0);
1431
	v = max(v, s17);
1432
	if ((u - bboxDepth(supBBox)) - (bboxHeight(subBBox) - v) < 4 * theta) {
1433
	    double psi = 0.8 * s5 - (u - bboxDepth(supBBox));
1434
	    if (psi > 0) {
1435
		u += psi;
1436
		v -= psi;
1437
	    }
1438
	}
1439
	if (draw)
3244 ihaka 1440
	    PMoveTo(savedX, savedY);
2028 ihaka 1441
	subBBox = RenderOffsetElement(sub, width, -v, draw);
1442
	if (draw)
3244 ihaka 1443
	    PMoveTo(savedX, savedY);
2028 ihaka 1444
	SetSupStyle(style);
1445
	supBBox = RenderOffsetElement(sup, width + delta, u, draw);
1446
	bodyBBox = CombineAlignedBBoxes(bodyBBox, subBBox);
1447
	bodyBBox = CombineAlignedBBoxes(bodyBBox, supBBox);
1448
    }
1449
    else {
1450
	supBBox = RenderOffsetElement(sup, 0, u, draw);
1451
	bodyBBox = CombineBBoxes(bodyBBox, supBBox);
1452
    }
1453
    if (draw)
3244 ihaka 1454
	PMoveTo(savedX + bboxWidth(bodyBBox), savedY);
2028 ihaka 1455
    SetStyle(style);
1456
    return bodyBBox;
2 r 1457
}
1458
 
1459
 
2028 ihaka 1460
/*----------------------------------------------------------------------
1461
 *
1462
 *  Code for Accented Expressions (widehat, bar, widetilde, ...)
1463
 *
1464
 */
2 r 1465
 
2028 ihaka 1466
#define ACCENT_GAP  0.2
1467
#define HAT_HEIGHT  0.3
2 r 1468
 
3475 pd 1469
#define NTILDE	    8
1470
#define DELTA	    0.05
2 r 1471
 
2028 ihaka 1472
static int WideTildeAtom(SEXP expr)
2 r 1473
{
2028 ihaka 1474
    return NameAtom(expr) && NameMatch(expr, "widetilde");
2 r 1475
}
1476
 
2028 ihaka 1477
static BBOX RenderWideTilde(SEXP expr, int draw)
2 r 1478
{
2028 ihaka 1479
    double savedX = CurrentX;
1480
    double savedY = CurrentY;
1481
    BBOX bbox = RenderElement(CADR(expr), draw);
1482
    double height = bboxHeight(bbox);
2124 maechler 1483
    /*double width = bboxWidth(bbox);*/
2028 ihaka 1484
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1485
    double delta = totalwidth * (1 - 2 * DELTA) / NTILDE;
1486
    double start = DELTA * totalwidth;
2105 ihaka 1487
    double accentGap = ACCENT_GAP * XHeight();
1488
    double hatHeight = 0.5 * HAT_HEIGHT * XHeight();
2028 ihaka 1489
    double c = 8 * atan(1.0) / NTILDE;
1490
    double x[NTILDE + 3], y[NTILDE + 3];
1491
    double baseX, baseY, xval, yval;
1492
    int i;
2 r 1493
 
2028 ihaka 1494
    if (draw) {
1495
	baseX = savedX;
1496
	baseY = savedY + height + accentGap;
3244 ihaka 1497
	PMoveTo(baseX, baseY);
2028 ihaka 1498
	x[0] = ConvertedX();
1499
	y[0] = ConvertedY();
1500
	for (i = 0; i <= NTILDE; i++) {
1501
	    xval = start + i * delta;
1502
	    yval = 0.5 * hatHeight * (sin(c * i) + 1);
3244 ihaka 1503
	    PMoveTo(baseX + xval, baseY + yval);
2028 ihaka 1504
	    x[i + 1] = ConvertedX();
1505
	    y[i + 1] = ConvertedY();
1506
	}
3244 ihaka 1507
	PMoveTo(baseX + totalwidth, baseY + hatHeight);
2028 ihaka 1508
	x[NTILDE + 2] = ConvertedX();
1509
	y[NTILDE + 2] = ConvertedY();
1510
	GPolyline(NTILDE + 3, x, y, INCHES, MathDevice);
3244 ihaka 1511
	PMoveTo(savedX + totalwidth, savedY);
2028 ihaka 1512
    }
1513
    return MakeBBox(height + accentGap + hatHeight,
1514
		    bboxDepth(bbox), totalwidth);
2 r 1515
}
1516
 
2028 ihaka 1517
static int WideHatAtom(SEXP expr)
2 r 1518
{
2028 ihaka 1519
    return NameAtom(expr) && NameMatch(expr, "widehat");
2 r 1520
}
1521
 
2028 ihaka 1522
static BBOX RenderWideHat(SEXP expr, int draw)
2 r 1523
{
2028 ihaka 1524
    double savedX = CurrentX;
1525
    double savedY = CurrentY;
1526
    BBOX bbox = RenderElement(CADR(expr), draw);
2105 ihaka 1527
    double accentGap = ACCENT_GAP * XHeight();
1528
    double hatHeight = HAT_HEIGHT * XHeight();
2028 ihaka 1529
    double totalwidth = bboxWidth(bbox) + bboxItalic(bbox);
1530
    double height = bboxHeight(bbox);
1531
    double width = bboxWidth(bbox);
1532
    double x[3], y[3];
2 r 1533
 
2028 ihaka 1534
    if (draw) {
3244 ihaka 1535
	PMoveTo(savedX, savedY + height + accentGap);
2028 ihaka 1536
	x[0] = ConvertedX();
1537
	y[0] = ConvertedY();
3244 ihaka 1538
	PMoveAcross(0.5 * totalwidth);
1539
	PMoveUp(hatHeight);
2028 ihaka 1540
	x[1] = ConvertedX();
1541
	y[1] = ConvertedY();
3244 ihaka 1542
	PMoveAcross(0.5 * totalwidth);
1543
	PMoveUp(-hatHeight);
2028 ihaka 1544
	x[2] = ConvertedX();
1545
	y[2] = ConvertedY();
1546
	GPolyline(3, x, y, INCHES, MathDevice);
3244 ihaka 1547
	PMoveTo(savedX + width, savedY);
2028 ihaka 1548
    }
1549
    return EnlargeBBox(bbox, accentGap + hatHeight, 0, 0);
2 r 1550
}
1551
 
2028 ihaka 1552
static int BarAtom(SEXP expr)
2 r 1553
{
2028 ihaka 1554
    return NameAtom(expr) && NameMatch(expr, "bar");
2 r 1555
}
1556
 
2028 ihaka 1557
static BBOX RenderBar(SEXP expr, int draw)
2 r 1558
{
2028 ihaka 1559
    double savedX = CurrentX;
1560
    double savedY = CurrentY;
1561
    BBOX bbox = RenderElement(CADR(expr), draw);
2105 ihaka 1562
    double accentGap = ACCENT_GAP * XHeight();
2124 maechler 1563
    /*double hatHeight = HAT_HEIGHT * XHeight();*/
2028 ihaka 1564
    double height = bboxHeight(bbox);
1565
    double width = bboxWidth(bbox);
2105 ihaka 1566
    double offset = bboxItalic(bbox);
2028 ihaka 1567
    double x[2], y[2];
2 r 1568
 
2028 ihaka 1569
    if (draw) {
3244 ihaka 1570
	PMoveTo(savedX + offset, savedY + height + accentGap);
2028 ihaka 1571
	x[0] = ConvertedX();
1572
	y[0] = ConvertedY();
3244 ihaka 1573
	PMoveAcross(width);
2028 ihaka 1574
	x[1] = ConvertedX();
1575
	y[1] = ConvertedY();
1576
	GPolyline(2, x, y, INCHES, MathDevice);
3244 ihaka 1577
	PMoveTo(savedX + width, savedY);
2028 ihaka 1578
    }
1579
    return EnlargeBBox(bbox, accentGap, 0, 0);
2 r 1580
}
1581
 
2028 ihaka 1582
static struct {
1583
    char *name;
1584
    int code;
2 r 1585
}
2028 ihaka 1586
AccentTable[] = {
3475 pd 1587
    "hat",	      94,
1588
    "ring",	     176,
1589
    "tilde",	     126,
1590
    NULL,	       0,
2028 ihaka 1591
};
2122 maechler 1592
 
2028 ihaka 1593
static int AccentCode(SEXP expr)
2 r 1594
{
2028 ihaka 1595
    int i;
1596
    for (i = 0; AccentTable[i].code; i++)
1597
	if (NameMatch(expr, AccentTable[i].name))
1598
	    return AccentTable[i].code;
1599
    return 0;
2 r 1600
}
1601
 
2028 ihaka 1602
static int AccentAtom(SEXP expr)
2 r 1603
{
2105 ihaka 1604
    return NameAtom(expr) && (AccentCode(expr) != 0);
2 r 1605
}
1606
 
2028 ihaka 1607
static void InvalidAccent(SEXP expr)
2 r 1608
{
2028 ihaka 1609
    errorcall(expr, "invalid accent\n");
2 r 1610
}
1611
 
2028 ihaka 1612
static BBOX RenderAccent(SEXP expr, int draw)
2 r 1613
{
2028 ihaka 1614
    SEXP body, accent;
1615
    double savedX = CurrentX;
1616
    double savedY = CurrentY;
1617
    BBOX bodyBBox, accentBBox;
2105 ihaka 1618
    double xoffset, yoffset, width, italic;
2028 ihaka 1619
    int code;
1620
    if (length(expr) != 2)
1621
	InvalidAccent(expr);
1622
    accent = CAR(expr);
1623
    body = CADR(expr);
2105 ihaka 1624
    code = AccentCode(accent);
1625
    if (code == 0)
2028 ihaka 1626
	InvalidAccent(expr);
2105 ihaka 1627
    bodyBBox = RenderElement(body, 0);
1628
    italic = bboxItalic(bodyBBox);
2028 ihaka 1629
    accentBBox = RenderChar(code, 0);
2105 ihaka 1630
    width = max(bboxWidth(bodyBBox) + bboxItalic(bodyBBox),
1631
		bboxWidth(accentBBox));
1632
    xoffset = 0.5 *(width - bboxWidth(bodyBBox));
1633
    bodyBBox = RenderGap(xoffset, draw);
1634
    bodyBBox = CombineBBoxes(bodyBBox, RenderElement(body, draw));
1635
    bodyBBox = CombineBBoxes(bodyBBox, RenderGap(xoffset, draw));
3244 ihaka 1636
    PMoveTo(savedX, savedY);
2105 ihaka 1637
    xoffset = 0.5 *(width - bboxWidth(accentBBox))
1638
	+ 0.9 * italic;
1639
    yoffset = bboxHeight(bodyBBox) + bboxDepth(accentBBox) + 0.1 * XHeight();
2028 ihaka 1640
    if (draw) {
3244 ihaka 1641
	PMoveTo(savedX + xoffset, savedY + yoffset);
2028 ihaka 1642
	RenderChar(code, draw);
1643
    }
1644
    bodyBBox = CombineOffsetBBoxes(bodyBBox, 0, accentBBox, 0,
1645
				   xoffset, yoffset);
3244 ihaka 1646
    PMoveTo(savedX + width, savedY);
2028 ihaka 1647
    return bodyBBox;
2 r 1648
}
1649
 
1650
 
2028 ihaka 1651
/*----------------------------------------------------------------------
1652
 *
1653
 *  Code for Fraction Expressions  (over, atop)
1654
 *
1655
 *  Rules 15, 15a, ..., 15e of the TeXBook
1656
 *
1657
 */
2 r 1658
 
2028 ihaka 1659
static void NumDenomVShift(BBOX numBBox, BBOX denomBBox,
1660
			     double *u, double *v)
2 r 1661
{
2028 ihaka 1662
    double a, delta, phi, theta;
1663
    a = TeX(sigma22);
1664
    theta = TeX(xi8);
1665
    if(CurrentStyle > STYLE_T) {
1666
	*u = TeX(sigma8);
1667
	*v = TeX(sigma11);
1668
	phi = 3 * theta;
1669
    }
1670
    else {
1671
	*u = TeX(sigma9);
1672
	*v = TeX(sigma12);
1673
	phi = theta;
1674
    }
1675
    delta = (*u - bboxDepth(numBBox)) - (a + 0.5 * theta);
1676
    if (delta < phi)
2105 ihaka 1677
	*u += (phi - delta) + theta;
2028 ihaka 1678
    delta = (a + 0.5 * theta) - (bboxHeight(denomBBox) - *v);
1679
    if (delta < phi)
2105 ihaka 1680
	*v += (phi - delta) + theta;
2 r 1681
}
1682
 
2028 ihaka 1683
static void NumDenomHShift(BBOX numBBox, BBOX denomBBox,
1684
			   double *numShift, double *denomShift)
2 r 1685
{
2028 ihaka 1686
    double numWidth = bboxWidth(numBBox);
1687
    double denomWidth = bboxWidth(denomBBox);
1688
    if (numWidth > denomWidth) {
1689
	*numShift = 0;
1690
	*denomShift = (numWidth - denomWidth) / 2;
1691
    }
1692
    else {
1693
	*numShift = (denomWidth - numWidth) / 2;
1694
	*denomShift = 0;
1695
    }
2 r 1696
}
1697
 
2028 ihaka 1698
static BBOX RenderFraction(SEXP expr, int rule, int draw)
2 r 1699
{
2028 ihaka 1700
    SEXP numerator = CADR(expr);
1701
    SEXP denominator = CADDR(expr);
2124 maechler 1702
    BBOX numBBox, denomBBox;
2028 ihaka 1703
    double nHShift, dHShift;
1704
    double nVShift, dVShift;
1705
    double width, x[2], y[2];
1706
    double savedX = CurrentX;
1707
    double savedY = CurrentY;
1708
    STYLE style;
2 r 1709
 
2028 ihaka 1710
    style = GetStyle();
1711
    SetNumStyle(style);
1712
    numBBox = RenderItalicCorr(RenderElement(numerator, 0), 0);
1713
    SetDenomStyle(style);
1714
    denomBBox = RenderItalicCorr(RenderElement(denominator, 0), 0);
1715
    SetStyle(style);
2 r 1716
 
2028 ihaka 1717
    width = max(bboxWidth(numBBox), bboxWidth(denomBBox));
1718
    NumDenomHShift(numBBox, denomBBox, &nHShift, &dHShift);
1719
    NumDenomVShift(numBBox, denomBBox, &nVShift, &dVShift);
2 r 1720
 
2028 ihaka 1721
    CurrentX = savedX;
1722
    CurrentY = savedY;
1723
    SetNumStyle(style);
1724
    numBBox = RenderOffsetElement(numerator, nHShift, nVShift, draw);
2 r 1725
 
2028 ihaka 1726
    CurrentX = savedX;
1727
    CurrentY = savedY;
1728
    SetDenomStyle(style);
1729
    denomBBox = RenderOffsetElement(denominator, dHShift, -dVShift, draw);
2 r 1730
 
2028 ihaka 1731
    SetStyle(style);
2 r 1732
 
2028 ihaka 1733
    if (draw) {
1734
	if (rule) {
1735
	    CurrentX = savedX;
1736
	    CurrentY = savedY;
3244 ihaka 1737
	    PMoveUp(AxisHeight());
2028 ihaka 1738
	    x[0] = ConvertedX();
1739
	    y[0] = ConvertedY();
3244 ihaka 1740
	    PMoveAcross(width);
2028 ihaka 1741
	    x[1] = ConvertedX();
1742
	    y[1] = ConvertedY();
1743
	    GPolyline(2, x, y, INCHES, MathDevice);
3244 ihaka 1744
	    PMoveUp(-AxisHeight());
2028 ihaka 1745
	}
3244 ihaka 1746
	PMoveTo(savedX + width, savedY);
2028 ihaka 1747
    }
1748
    return CombineAlignedBBoxes(numBBox, denomBBox);
2 r 1749
}
1750
 
2028 ihaka 1751
static int OverAtom(SEXP expr)
2 r 1752
{
2105 ihaka 1753
    return NameAtom(expr) &&
3475 pd 1754
	(NameMatch(expr, "over") || NameMatch(expr, "frac"));
2 r 1755
}
1756
 
2028 ihaka 1757
static BBOX RenderOver(SEXP expr, int draw)
2 r 1758
{
2028 ihaka 1759
    return RenderFraction(expr, 1, draw);
2 r 1760
}
1761
 
2028 ihaka 1762
static int AtopAtom(SEXP expr)
2 r 1763
{
2028 ihaka 1764
    return NameAtom(expr) && NameMatch(expr, "atop");
2 r 1765
}
1766
 
2028 ihaka 1767
static BBOX RenderAtop(SEXP expr, int draw)
2 r 1768
{
2028 ihaka 1769
    return RenderFraction(expr, 0, draw);
2 r 1770
}
2105 ihaka 1771
 
2028 ihaka 1772
/*----------------------------------------------------------------------
1773
 *
1774
 *  Code for Grouped Expressions  (e.g. ( ... ))
1775
 *
1776
 *    group(ldelim, body, rdelim)
1777
 *
1778
 *    bgroup(ldelim, body, rdelim)
1779
 *
1780
 */
2 r 1781
 
2105 ihaka 1782
#define DelimSymbolMag 1.25
1783
 
2028 ihaka 1784
static int DelimCode(SEXP expr, SEXP head)
2 r 1785
{
2028 ihaka 1786
    int code = 0;
1787
    if (NameAtom(head)) {
1788
	if (NameMatch(head, "lfloor"))
1789
	    code = S_BRACKETLEFTBT;
1790
	else if (NameMatch(head, "rfloor"))
1791
	    code = S_BRACKETRIGHTBT;
1792
	if (NameMatch(head, "lceil"))
1793
	    code = S_BRACKETLEFTBT;
1794
	else if (NameMatch(head, "rceil"))
1795
	    code = S_BRACKETRIGHTBT;
1796
    }
1797
    else if (StringAtom(head) && length(head) > 0) {
1798
	if (StringMatch(head, "|"))
1799
	    code = '|';
1800
	else if (StringMatch(head, "||"))
1801
	    code = 2;
1802
	else if (StringMatch(head, "("))
1803
	    code = '(';
1804
	else if (StringMatch(head, ")"))
1805
	    code = ')';
1806
	else if (StringMatch(head, "["))
1807
	    code = '[';
1808
	else if (StringMatch(head, "]"))
1809
	    code = ']';
1810
	else if (StringMatch(head, "{"))
1811
	    code = '{';
1812
	else if (StringMatch(head, "}"))
1813
	    code = '}';
1814
	else if (StringMatch(head, "") || StringMatch(head, "."))
1815
	    code = '.';
1816
    }
1817
    if (code == 0)
1818
	errorcall(expr, "invalid group delimiter\n");
1819
    return code;
1016 maechler 1820
}
2 r 1821
 
2105 ihaka 1822
static BBOX RenderDelimiter(int delim, int draw)
1823
{
1824
    BBOX bbox;
1825
    double savecex = MathDevice->gp.cex;
1826
    MathDevice->gp.cex = DelimSymbolMag * MathDevice->gp.cex;
1827
    bbox = RenderSymbolChar(delim, draw);
1828
    MathDevice->gp.cex = savecex;
1829
    return bbox;
1830
}
1831
 
2028 ihaka 1832
static int GroupAtom(SEXP expr)
2 r 1833
{
2028 ihaka 1834
    return NameAtom(expr) && NameMatch(expr, "group");
2 r 1835
}
1836
 
2028 ihaka 1837
static BBOX RenderGroup(SEXP expr, int draw)
2 r 1838
{
2105 ihaka 1839
    double cexSaved = MathDevice->gp.cex;
2028 ihaka 1840
    BBOX bbox;
1841
    int code;
1842
    if (length(expr) != 4)
1843
	errorcall(expr, "invalid group specification\n");
1844
    bbox = NullBBox();
1845
    code = DelimCode(expr, CADR(expr));
2105 ihaka 1846
    MathDevice->gp.cex = DelimSymbolMag * MathDevice->gp.cex;
2028 ihaka 1847
    if (code == 2) {
1848
	bbox = RenderSymbolChar('|', draw);
1849
	bbox = RenderSymbolChar('|', draw);
1850
    }
1851
    else if (code != '.')
1852
	bbox = RenderSymbolChar(code, draw);
2105 ihaka 1853
    MathDevice->gp.cex = cexSaved;
2028 ihaka 1854
    bbox = CombineBBoxes(bbox, RenderElement(CADDR(expr), draw));
1855
    bbox = RenderItalicCorr(bbox, draw);
1856
    code = DelimCode(expr, CADDDR(expr));
2105 ihaka 1857
    MathDevice->gp.cex = DelimSymbolMag * MathDevice->gp.cex;
2028 ihaka 1858
    if (code == 2) {
1859
	bbox = RenderSymbolChar('|', draw);
1860
	bbox = RenderSymbolChar('|', draw);
1861
    }
1862
    else if (code != '.')
1863
	bbox = RenderSymbolChar(code, draw);
2105 ihaka 1864
    MathDevice->gp.cex = cexSaved;
2028 ihaka 1865
    return bbox;
2 r 1866
}
1867
 
2028 ihaka 1868
static int BGroupAtom(SEXP expr)
2 r 1869
{
2028 ihaka 1870
    return NameAtom(expr) && NameMatch(expr, "bgroup");
2 r 1871
}
1872
 
2028 ihaka 1873
static BBOX RenderDelim(int which, double dist, int draw)
2 r 1874
{
2028 ihaka 1875
    double savedX = CurrentX;
1876
    double savedY = CurrentY;
1877
    FontType prev = SetFont(SymbolFont);
1878
    BBOX ansBBox, topBBox, botBBox, extBBox, midBBox;
1879
    int top, bot, ext, mid;
2105 ihaka 1880
    int i, n;
1881
    double topShift, botShift, extShift, midShift;
1882
    double ytop, ybot, extHeight, delta;
2028 ihaka 1883
    double axisHeight = TeX(sigma22);
2 r 1884
 
2028 ihaka 1885
    switch(which) {
1886
    case '.':
1887
	return NullBBox();
1888
	break;
1889
    case '|':
1890
    case 2:
1891
	top = 239; ext = 239; bot = 239; mid = 0;
1892
	break;
1893
    case '(':
1894
	top = 230; ext = 231; bot = 232; mid = 0;
1895
	break;
1896
    case ')':
1897
	top = 246; ext = 247; bot = 248; mid = 0;
1898
	break;
1899
    case '[':
1900
	top = 233; ext = 234; bot = 235; mid = 0;
1901
	break;
1902
    case ']':
1903
	top = 249; ext = 250; bot = 251; mid = 0;
1904
	break;
1905
    case '{':
1906
	top = 236; ext = 239; bot = 238; mid = 237;
2122 maechler 1907
	break;
2028 ihaka 1908
    case '}':
1909
	top = 252; ext = 239; bot = 254; mid = 253;
1910
	break;
1911
    default:
1912
	error("group is incomplete\n");
3475 pd 1913
	return ansBBox;/*never reached*/
2028 ihaka 1914
    }
1915
    topBBox = GlyphBBox(top);
1916
    extBBox = GlyphBBox(ext);
1917
    botBBox = GlyphBBox(bot);
2105 ihaka 1918
    if (which == '{' || which == '}') {
1919
	if (1.2 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
1920
	    dist = 1.2 * (bboxHeight(topBBox) + bboxDepth(botBBox));
1921
    }
1922
    else {
1923
	if (0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox)) > dist)
1924
	    dist = 0.8 * (bboxHeight(topBBox) + bboxDepth(topBBox));
1925
    }
1926
    extHeight = bboxHeight(extBBox) + bboxDepth(extBBox);
2028 ihaka 1927
    topShift = dist - bboxHeight(topBBox) + axisHeight;
1928
    botShift = dist - bboxDepth(botBBox) - axisHeight;
2105 ihaka 1929
    extShift = 0.5 * (bboxHeight(extBBox) - bboxDepth(extBBox));
2028 ihaka 1930
    topBBox = ShiftBBox(topBBox, topShift);
1931
    botBBox = ShiftBBox(botBBox, -botShift);
1932
    ansBBox = CombineAlignedBBoxes(topBBox, botBBox);
2105 ihaka 1933
    if (which == '{' || which == '}') {
1934
	midBBox = GlyphBBox(mid);
1935
	midShift = axisHeight
1936
	    - 0.5 * (bboxHeight(midBBox) - bboxDepth(midBBox));
1937
	midBBox = ShiftBBox(midBBox, midShift);
1938
	ansBBox = CombineAlignedBBoxes(ansBBox, midBBox);
1939
	if (draw) {
3244 ihaka 1940
	    PMoveTo(savedX, savedY + topShift);
2105 ihaka 1941
	    RenderSymbolChar(top, draw);
3244 ihaka 1942
	    PMoveTo(savedX, savedY + midShift);
2122 maechler 1943
	    RenderSymbolChar(mid, draw);
3244 ihaka 1944
	    PMoveTo(savedX, savedY - botShift);
2105 ihaka 1945
	    RenderSymbolChar(bot, draw);
3244 ihaka 1946
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY);
2105 ihaka 1947
	}
2028 ihaka 1948
    }
2105 ihaka 1949
    else {
1950
	if (draw) {
1951
	    /* draw the top and bottom elements */
3244 ihaka 1952
	    PMoveTo(savedX, savedY + topShift);
2105 ihaka 1953
	    RenderSymbolChar(top, draw);
3244 ihaka 1954
	    PMoveTo(savedX, savedY - botShift);
2105 ihaka 1955
	    RenderSymbolChar(bot, draw);
1956
	    /* now join with extenders */
1957
	    ytop = axisHeight + dist
1958
		- (bboxHeight(topBBox) + bboxDepth(topBBox));
1959
	    ybot = axisHeight - dist
1960
		+ (bboxHeight(botBBox) + bboxDepth(botBBox));
1961
	    n = ceil((ytop - ybot) / (0.99 * extHeight));
1962
	    if (n > 0) {
1963
		delta = (ytop - ybot) / n;
1964
		for (i = 0; i < n; i++) {
3244 ihaka 1965
		    PMoveTo(savedX, savedY + ybot + (i + 0.5) * delta - extShift);
2105 ihaka 1966
		    RenderSymbolChar(ext, draw);
1967
		}
1968
	    }
3244 ihaka 1969
	    PMoveTo(savedX + bboxWidth(ansBBox), savedY);
2122 maechler 1970
 
2105 ihaka 1971
	}
1972
    }
2028 ihaka 1973
    SetFont(prev);
1974
    return ansBBox;
2 r 1975
}
1976
 
2028 ihaka 1977
static BBOX RenderBGroup(SEXP expr, int draw)
2 r 1978
{
2028 ihaka 1979
    double dist;
2124 maechler 1980
    BBOX bbox;
2028 ihaka 1981
    double axisHeight = TeX(sigma22);
1982
    double extra = 0.2 * xHeight();
1983
    int delim1, delim2;
1984
    if (length(expr) != 4)
1985
	errorcall(expr, "invalid group specification\n");
1986
    bbox = NullBBox();
1987
    delim1 = DelimCode(expr, CADR(expr));
1988
    delim2 = DelimCode(expr, CADDDR(expr));
1989
    bbox = RenderElement(CADDR(expr), 0);
1990
    dist = max(bboxHeight(bbox) - axisHeight, bboxDepth(bbox) + axisHeight);
1991
    bbox = RenderDelim(delim1, dist + extra, draw);
3475 pd 1992
    bbox = CombineBBoxes(bbox,	RenderElement(CADDR(expr), draw));
2028 ihaka 1993
    bbox = RenderItalicCorr(bbox, draw);
3475 pd 1994
    bbox = CombineBBoxes(bbox,	RenderDelim(delim2, dist + extra, draw));
2028 ihaka 1995
    return bbox;
2 r 1996
}
1997
 
2028 ihaka 1998
/*----------------------------------------------------------------------
1999
 *
2000
 *  Code for Parenthetic Expressions  (i.e. ( ... ))
2001
 *
2002
 */
2 r 2003
 
2028 ihaka 2004
static int ParenAtom(SEXP expr)
2 r 2005
{
2028 ihaka 2006
    return NameAtom(expr) && NameMatch(expr, "(");
2 r 2007
}
2008
 
2028 ihaka 2009
static BBOX RenderParen(SEXP expr, int draw)
2 r 2010
{
2028 ihaka 2011
    BBOX bbox;
2105 ihaka 2012
    bbox = RenderDelimiter(S_PARENLEFT, draw);
2028 ihaka 2013
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw));
2014
    bbox = RenderItalicCorr(bbox, draw);
2105 ihaka 2015
    return CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw));
2 r 2016
}
2017
 
2028 ihaka 2018
/*----------------------------------------------------------------------
2019
 *
2020
 *  Code for Integral Operators.
2021
 *
2022
 */
2 r 2023
 
2028 ihaka 2024
static int IntAtom(SEXP expr)
2 r 2025
{
2028 ihaka 2026
    return NameAtom(expr) && NameMatch(expr, "integral");
2 r 2027
}
2028
 
1926 ihaka 2029
 
2028 ihaka 2030
static BBOX RenderIntSymbol(int draw)
1926 ihaka 2031
{
2028 ihaka 2032
    double savedX = CurrentX;
2033
    double savedY = CurrentY;
2105 ihaka 2034
    if (GetStyle() > STYLE_T) {
2035
	BBOX bbox1 = RenderSymbolChar(243, 0);
2036
	BBOX bbox2 = RenderSymbolChar(245, 0);
2037
	double shift;
2038
	shift = TeX(sigma22) + 0.99 * bboxDepth(bbox1);
3244 ihaka 2039
	PMoveUp(shift);
2105 ihaka 2040
	bbox1 = ShiftBBox(RenderSymbolChar(243, draw), shift);
2041
	CurrentX = savedX;
2042
	CurrentY = savedY;
2043
	shift = TeX(sigma22) - 0.99 * bboxHeight(bbox2);
3244 ihaka 2044
	PMoveUp(shift);
2105 ihaka 2045
	bbox2 = ShiftBBox(RenderSymbolChar(245, draw), shift);
2046
	if (draw)
3244 ihaka 2047
	    PMoveTo(savedX + max(bboxWidth(bbox1), bboxWidth(bbox2)), savedY);
2105 ihaka 2048
	else
3244 ihaka 2049
	    PMoveTo(savedX, savedY);
2105 ihaka 2050
	return CombineAlignedBBoxes(bbox1, bbox2);
2051
    }
2052
    else {
2053
	return RenderSymbolChar(0362, draw);
2054
    }
1926 ihaka 2055
}
2056
 
2028 ihaka 2057
static BBOX RenderInt(SEXP expr, int draw)
2 r 2058
{
2028 ihaka 2059
    BBOX opBBox, lowerBBox, upperBBox, bodyBBox;
2060
    int nexpr = length(expr);
2061
    STYLE style = GetStyle();
2062
    double savedX = CurrentX;
2063
    double savedY = CurrentY;
2064
    double hshift, vshift, width;
2 r 2065
 
2028 ihaka 2066
    opBBox = RenderIntSymbol(draw);
2067
    width = bboxWidth(opBBox);
2068
    CurrentX = savedX;
2069
    CurrentY = savedY;
2070
    if (nexpr > 2) {
2071
	hshift = 0.5 * width + ThinSpace();
2072
	SetSubStyle(style);
2073
	lowerBBox = RenderElement(CADDR(expr), 0);
2074
	vshift = bboxDepth(opBBox) + CenterShift(lowerBBox);
2075
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -vshift, draw);
2076
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
2077
	SetStyle(style);
2078
	CurrentX = savedX;
2079
	CurrentY = savedY;
1839 ihaka 2080
    }
2028 ihaka 2081
    if (nexpr > 3) {
2082
	hshift = width + ThinSpace();
2083
	SetSupStyle(style);
2084
	upperBBox = RenderElement(CADDDR(expr), 0);
2085
	vshift = bboxHeight(opBBox) - CenterShift(upperBBox);
2086
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, vshift, draw);
2087
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
2088
	SetStyle(style);
2089
	CurrentX = savedX;
2090
	CurrentY = savedY;
1839 ihaka 2091
    }
3244 ihaka 2092
    PMoveAcross(bboxWidth(opBBox));
2028 ihaka 2093
    if (nexpr > 1) {
2094
	bodyBBox = RenderElement(CADR(expr), draw);
2095
	opBBox = CombineBBoxes(opBBox, bodyBBox);
1839 ihaka 2096
    }
2028 ihaka 2097
    return opBBox;
2 r 2098
}
2099
 
2100
 
2028 ihaka 2101
/*----------------------------------------------------------------------
2102
 *
2103
 *  Code for Operator Expressions (sum, product, lim, inf, sup, ...)
2104
 *
2105
 */
2 r 2106
 
2028 ihaka 2107
#define OperatorSymbolMag  1.25
2 r 2108
 
2028 ihaka 2109
static SymTab OpTable[] = {
3475 pd 2110
    "prod",	     S_PRODUCT,
2111
    "sum",	     S_SUM,
2112
    "union",	     S_UNION,
2028 ihaka 2113
    "intersect",     S_INTERSECTION,
3475 pd 2114
    "lim",	     N_LIM,
2115
    "liminf",	     N_LIMINF,
2116
    "limsup",	     N_LIMINF,
2117
    "inf",	     N_INF,
2118
    "sup",	     N_SUP,
2119
    "min",	     N_MIN,
2120
    "max",	     N_MAX,
2121
    NULL,	     0
2028 ihaka 2122
};
2 r 2123
 
2028 ihaka 2124
static int OpAtom(SEXP expr)
2 r 2125
{
2028 ihaka 2126
    int i;
2127
    for (i = 0; OpTable[i].code; i++)
2128
	if (NameMatch(expr, OpTable[i].name))
2129
	    return OpTable[i].code;
2130
    return 0;
2 r 2131
}
2132
 
2028 ihaka 2133
static BBOX RenderOpSymbol(SEXP op, int draw)
2 r 2134
{
2028 ihaka 2135
    BBOX bbox;
2136
    double cexSaved = MathDevice->gp.cex;
2124 maechler 2137
    /*double savedX = CurrentX;*/
2138
    /*double savedY = CurrentY;*/
2028 ihaka 2139
    double shift;
2105 ihaka 2140
    int display = (GetStyle() > STYLE_T);
2028 ihaka 2141
    int opId = OpAtom(op);
2 r 2142
 
2028 ihaka 2143
    if (opId == S_SUM || opId == S_PRODUCT) {
2105 ihaka 2144
	if (display) {
2145
	    MathDevice->gp.cex = OperatorSymbolMag * MathDevice->gp.cex;
2146
	    bbox = RenderSymbolChar(OpAtom(op), 0);
2147
	    shift = 0.5 * (bboxHeight(bbox) - bboxDepth(bbox)) - TeX(sigma22);
2148
	    if (draw) {
3244 ihaka 2149
		PMoveUp(-shift);
2105 ihaka 2150
		bbox = RenderSymbolChar(opId, 1);
3244 ihaka 2151
		PMoveUp(shift);
2105 ihaka 2152
	    }
2153
	    MathDevice->gp.cex = cexSaved;
2154
	    return ShiftBBox(bbox, -shift);
2028 ihaka 2155
	}
2105 ihaka 2156
	else return RenderSymbolChar(opId, draw);
2028 ihaka 2157
    }
1839 ihaka 2158
    else {
2028 ihaka 2159
	FontType prevfont = SetFont(PlainFont);
2160
	bbox = RenderStr(CHAR(PRINTNAME(op)), draw);
2161
	SetFont(prevfont);
2162
	return bbox;
1839 ihaka 2163
    }
2 r 2164
}
2165
 
2028 ihaka 2166
static BBOX RenderOp(SEXP expr, int draw)
2 r 2167
{
2028 ihaka 2168
    BBOX lowerBBox, upperBBox, bodyBBox;
2169
    double savedX = CurrentX;
2170
    double savedY = CurrentY;
2171
    int nexpr = length(expr);
2172
    STYLE style = GetStyle();
2173
    BBOX opBBox = RenderOpSymbol(CAR(expr), 0);
2174
    double width = bboxWidth(opBBox);
2175
    double hshift, lvshift, uvshift;
2176
    if (nexpr > 2) {
2177
	SetSubStyle(style);
2178
	lowerBBox = RenderElement(CADDR(expr), 0);
2179
	SetStyle(style);
2180
	width = max(width, bboxWidth(lowerBBox));
2181
	lvshift = max(TeX(xi10), TeX(xi12) - bboxHeight(lowerBBox));
2182
	lvshift = bboxDepth(opBBox) + bboxHeight(lowerBBox) + lvshift;
2183
    }
2184
    if (nexpr > 3) {
2185
	SetSupStyle(style);
2186
	upperBBox = RenderElement(CADDDR(expr), 0);
2187
	SetStyle(style);
2188
	width = max(width, bboxWidth(upperBBox));
2189
	uvshift = max(TeX(xi9), TeX(xi11) - bboxDepth(upperBBox));
2190
	uvshift = bboxHeight(opBBox) + bboxDepth(upperBBox) + uvshift;
2191
    }
2192
    hshift = 0.5 * (width - bboxWidth(opBBox));
2193
    opBBox = RenderGap(hshift, draw);
2194
    opBBox = CombineBBoxes(opBBox, RenderOpSymbol(CAR(expr), draw));
2195
    CurrentX = savedX;
2196
    CurrentY = savedY;
2197
    if (nexpr > 2) {
2198
	SetSubStyle(style);
2199
	hshift = 0.5 * (width - bboxWidth(lowerBBox));
2200
	lowerBBox = RenderOffsetElement(CADDR(expr), hshift, -lvshift, draw);
2201
	SetStyle(style);
2202
	opBBox = CombineAlignedBBoxes(opBBox, lowerBBox);
2203
	CurrentX = savedX;
2204
	CurrentY = savedY;
2205
    }
2206
    if (nexpr > 3) {
2207
	SetSupStyle(style);
2208
	hshift = 0.5 * (width - bboxWidth(upperBBox));
2209
	upperBBox = RenderOffsetElement(CADDDR(expr), hshift, uvshift, draw);
2210
	SetStyle(style);
2211
	opBBox = CombineAlignedBBoxes(opBBox, upperBBox);
2212
	CurrentX = savedX;
2213
	CurrentY = savedY;
2214
    }
2215
    opBBox = EnlargeBBox(opBBox, TeX(xi13), TeX(xi13), 0);
2216
    if (draw)
3244 ihaka 2217
	PMoveAcross(width);
2028 ihaka 2218
    opBBox = CombineBBoxes(opBBox, RenderGap(ThinSpace(), draw));
2219
    bodyBBox = RenderElement(CADR(expr), draw);
2220
    return CombineBBoxes(opBBox, bodyBBox);
2 r 2221
}
2222
 
2223
 
2028 ihaka 2224
/*----------------------------------------------------------------------
2225
 *
2226
 *  Code for radical expressions (root, sqrt)
2227
 *
2228
 *  Tunable parameteters :
2229
 *
3475 pd 2230
 *  RADICAL_GAP	   The gap between the nucleus and the radical extension.
2028 ihaka 2231
 *  RADICAL_SPACE  Extra space to the left and right of the nucleus.
2232
 *
2233
 */
2 r 2234
 
2028 ihaka 2235
#define RADICAL_GAP    0.4
2236
#define RADICAL_SPACE  0.2
2 r 2237
 
2028 ihaka 2238
static int RadicalAtom(SEXP expr)
2 r 2239
{
2028 ihaka 2240
    return NameAtom(expr) &&
2241
	(NameMatch(expr, "root") ||
2242
	 NameMatch(expr, "sqrt"));
2 r 2243
}
2244
 
2028 ihaka 2245
static BBOX RenderScript(SEXP expr, int draw)
2 r 2246
{
2028 ihaka 2247
    BBOX bbox;
2248
    STYLE style = GetStyle();
2249
    SetSupStyle(style);
2250
    bbox = RenderElement(expr, draw);
2251
    SetStyle(style);
2252
    return bbox;
2 r 2253
}
2254
 
2028 ihaka 2255
static BBOX RenderRadical(SEXP expr, int draw)
2 r 2256
{
1839 ihaka 2257
    SEXP body = CADR(expr);
2028 ihaka 2258
    SEXP order = CADDR(expr);
2124 maechler 2259
    BBOX bodyBBox, orderBBox;
2028 ihaka 2260
    double radWidth, radHeight, radDepth;
2261
    double leadWidth, leadHeight, twiddleHeight;
2262
    double hshift, vshift;
2263
    double radGap, radSpace, radTrail;
2264
    STYLE style = GetStyle();
2265
    double savedX = CurrentX;
2266
    double savedY = CurrentY;
2267
    double x[5], y[5];
2 r 2268
 
2028 ihaka 2269
    radGap = RADICAL_GAP * xHeight();
2270
    radSpace = RADICAL_SPACE * xHeight();
2271
    radTrail = MuSpace();
2272
    SetPrimeStyle(style);
2273
    bodyBBox = RenderElement(body, 0);
2274
    bodyBBox = RenderItalicCorr(bodyBBox, 0);
2 r 2275
 
2028 ihaka 2276
    radWidth = 0.6 *XHeight();
2277
    radHeight = bboxHeight(bodyBBox) + radGap;
2278
    radDepth = bboxDepth(bodyBBox);
2279
    twiddleHeight = CenterShift(bodyBBox);
2 r 2280
 
2028 ihaka 2281
    leadWidth = radWidth;
2282
    leadHeight = radHeight;
2283
    if (order != R_NilValue) {
2284
	SetSupStyle(style);
2285
	orderBBox = RenderScript(order, 0);
2286
	leadWidth = max(leadWidth, bboxWidth(orderBBox) + 0.4 * radWidth);
2287
	hshift = leadWidth - bboxWidth(orderBBox) - 0.4 * radWidth;
2288
	vshift = leadHeight - bboxHeight(orderBBox);
2289
	if (vshift - bboxDepth(orderBBox) < twiddleHeight + radGap)
2290
	    vshift = twiddleHeight + bboxDepth(orderBBox) + radGap;
2291
	if (draw) {
3244 ihaka 2292
	    PMoveTo(savedX + hshift, savedY + vshift);
2028 ihaka 2293
	    orderBBox = RenderScript(order, draw);
2294
	}
2295
	orderBBox = EnlargeBBox(orderBBox, vshift, 0, hshift);
1839 ihaka 2296
    }
2028 ihaka 2297
    else
2298
	orderBBox = NullBBox();
2299
    if (draw) {
3244 ihaka 2300
	PMoveTo(savedX + leadWidth - radWidth, savedY);
2301
	PMoveUp(0.8 * twiddleHeight);
2028 ihaka 2302
	x[0] = ConvertedX();
2303
	y[0] = ConvertedY();
3244 ihaka 2304
	PMoveUp(0.2 * twiddleHeight);
2305
	PMoveAcross(0.3 * radWidth);
2028 ihaka 2306
	x[1] = ConvertedX();
2307
	y[1] = ConvertedY();
3244 ihaka 2308
	PMoveUp(-(twiddleHeight + bboxDepth(bodyBBox)));
2309
	PMoveAcross(0.3 * radWidth);
2028 ihaka 2310
	x[2] = ConvertedX();
2311
	y[2] = ConvertedY();
3244 ihaka 2312
	PMoveUp(bboxDepth(bodyBBox) + bboxHeight(bodyBBox) + radGap);
2313
	PMoveAcross(0.4 * radWidth);
2028 ihaka 2314
	x[3] = ConvertedX();
2315
	y[3] = ConvertedY();
3244 ihaka 2316
	PMoveAcross(radSpace + bboxWidth(bodyBBox) + radTrail);
2028 ihaka 2317
	x[4] = ConvertedX();
2318
	y[4] = ConvertedY();
2319
	GPolyline(5, x, y, INCHES, MathDevice);
3244 ihaka 2320
	PMoveTo(savedX, savedY);
2028 ihaka 2321
    }
2322
    orderBBox = CombineAlignedBBoxes(orderBBox,
2323
				     RenderGap(leadWidth + radSpace, draw));
2324
    SetPrimeStyle(style);
2325
    orderBBox = CombineBBoxes(orderBBox, RenderElement(body, draw));
2326
    orderBBox = CombineBBoxes(orderBBox, RenderGap(2 * radTrail, draw));
2327
    SetStyle(style);
2328
    return orderBBox;
2 r 2329
}
2330
 
2028 ihaka 2331
/*----------------------------------------------------------------------
2332
 *
2333
 *  Code for Absolute Value Expressions (abs)
2334
 *
2335
 */
2 r 2336
 
2028 ihaka 2337
static int AbsAtom(SEXP expr)
2 r 2338
{
2028 ihaka 2339
    return NameAtom(expr) && NameMatch(expr, "abs");
2 r 2340
}
2341
 
2028 ihaka 2342
static BBOX RenderAbs(SEXP expr, int draw)
2 r 2343
{
2028 ihaka 2344
    BBOX bbox = RenderElement(CADR(expr), 0);
2345
    double height = bboxHeight(bbox);
2346
    double depth = bboxDepth(bbox);
1839 ihaka 2347
    double x[2], y[2];
2 r 2348
 
2028 ihaka 2349
    bbox= RenderGap(MuSpace(), draw);
2350
    if (draw) {
3244 ihaka 2351
	PMoveUp(-depth);
2028 ihaka 2352
	x[0] = ConvertedX();
2353
	y[0] = ConvertedY();
3244 ihaka 2354
	PMoveUp(depth + height);
2028 ihaka 2355
	x[1] = ConvertedX();
2356
	y[1] = ConvertedY();
2357
	GPolyline(2, x, y, INCHES, MathDevice);
3244 ihaka 2358
	PMoveUp(-height);
2028 ihaka 2359
    }
2360
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(), draw));
2361
    bbox = CombineBBoxes(bbox, RenderElement(CADR(expr), draw));
2362
    bbox = RenderItalicCorr(bbox, draw);
2363
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(), draw));
2364
    if (draw) {
3244 ihaka 2365
	PMoveUp(-depth);
2028 ihaka 2366
	x[0] = ConvertedX();
2367
	y[0] = ConvertedY();
3244 ihaka 2368
	PMoveUp(depth + height);
2028 ihaka 2369
	x[1] = ConvertedX();
2370
	y[1] = ConvertedY();
2371
	GPolyline(2, x, y, INCHES, MathDevice);
3244 ihaka 2372
	PMoveUp(-height);
2028 ihaka 2373
    }
2374
    bbox = CombineBBoxes(bbox, RenderGap(MuSpace(), draw));
2375
    return bbox;
2 r 2376
}
2377
 
2028 ihaka 2378
/*----------------------------------------------------------------------
2379
 *
2380
 *  Code for Grouped Expressions (i.e. { ... } )
2381
 *
2382
 */
2 r 2383
 
2028 ihaka 2384
static int CurlyAtom(SEXP expr)
2 r 2385
{
2028 ihaka 2386
    return NameAtom(expr) &&
2387
	NameMatch(expr, "{");
2 r 2388
}
2389
 
2028 ihaka 2390
static BBOX RenderCurly(SEXP expr, int draw)
2 r 2391
{
2028 ihaka 2392
    return RenderElement(CADR(expr), draw);
2 r 2393
}
2394
 
2395
 
2028 ihaka 2396
/*----------------------------------------------------------------------
2397
 *
2398
 *  Code for Relation Expressions (i.e. ... ==, !=, ...)
2399
 *
2400
 */
2 r 2401
 
3475 pd 2402
				/* Binary Relationships */
2 r 2403
 
2028 ihaka 2404
SymTab RelTable[] = {
3475 pd 2405
    "<",		 60,	/* less */
2406
    "==",		 61,	/* equal */
2407
    ">",		 62,	/* greater */
2408
    "%=~%",		 64,	/* congruent */
2409
    "!=",		185,	/* not equal */
2410
    "<=",		163,	/* less or equal */
2411
    ">=",		179,	/* greater or equal */
2412
    "%==%",		186,	/* equivalence */
2413
    "%~~%",		187,	/* approxequal */
2 r 2414
 
3475 pd 2415
    "%<->%",		171,	/* Arrows */
2416
    "%<-%",		172,
2417
    "%up%",		173,
2418
    "%->%",		174,
2419
    "%down%",		175,
2420
    "%<=>%",		219,
2421
    "%<=%",		220,
2422
    "%dblup%",		221,
2423
    "%=>%",		222,
2424
    "%dbldown%",	223,
2 r 2425
 
3475 pd 2426
    "%supset%",		201,	/* Sets (TeX Names) */
2427
    "%supseteq%",	202,
2428
    "%notsubset%",	203,
2429
    "%subset%",		204,
2430
    "%subseteq%",	205,
2431
    "%in%",		206,
2432
    "%notin%",		207,
2 r 2433
 
3475 pd 2434
    NULL,		 0,
2028 ihaka 2435
};
1016 maechler 2436
 
2028 ihaka 2437
static int RelAtom(SEXP expr)
2 r 2438
{
2028 ihaka 2439
    int i;
2440
    for (i = 0; RelTable[i].code; i++)
2441
	if (NameMatch(expr, RelTable[i].name))
2442
	    return RelTable[i].code;
2443
    return 0;
2 r 2444
}
2445
 
2028 ihaka 2446
static BBOX RenderRel(SEXP expr, int draw)
2 r 2447
{
2028 ihaka 2448
    int op = RelAtom(CAR(expr));
2449
    int nexpr = length(expr);
2450
    BBOX bbox;
2451
    double gap;
2 r 2452
 
2028 ihaka 2453
    if(nexpr == 3) {
2122 maechler 2454
	gap = (CurrentStyle > STYLE_S) ? ThickSpace() : 0;
2028 ihaka 2455
	bbox = RenderElement(CADR(expr), draw);
2456
	bbox = RenderItalicCorr(bbox, draw);
2457
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
2458
	bbox = CombineBBoxes(bbox, RenderSymbolChar(op, draw));
2459
	bbox = CombineBBoxes(bbox, RenderGap(gap, draw));
2460
	return CombineBBoxes(bbox, RenderElement(CADDR(expr), draw));
2 r 2461
    }
2028 ihaka 2462
    else error("invalid mathematical annotation\n");
2 r 2463
}
2464
 
1016 maechler 2465
 
2028 ihaka 2466
/*----------------------------------------------------------------------
2467
 *
2468
 *  Code for Boldface Expressions
2469
 *
2470
 */
2 r 2471
 
2028 ihaka 2472
static int BoldAtom(SEXP expr)
2 r 2473
{
2028 ihaka 2474
    return NameAtom(expr) &&
2475
	NameMatch(expr, "bold");
2 r 2476
}
2477
 
2028 ihaka 2478
static BBOX RenderBold(SEXP expr, int draw)
2 r 2479
{
2028 ihaka 2480
    BBOX bbox;
2481
    FontType prevfont = SetFont(BoldFont);
2482
    bbox = RenderElement(CADR(expr), draw);
2483
    SetFont(prevfont);
2484
    return bbox;
2 r 2485
}
2486
 
2028 ihaka 2487
/*----------------------------------------------------------------------
2488
 *
2489
 *  Code for Italic Expressions
2490
 *
2491
 */
2 r 2492
 
2028 ihaka 2493
static int ItalicAtom(SEXP expr)
2 r 2494
{
2028 ihaka 2495
    return NameAtom(expr) &&
2496
	(NameMatch(expr, "italic") || NameMatch(expr, "math"));
2 r 2497
}
2498
 
2028 ihaka 2499
static BBOX RenderItalic(SEXP expr, int draw)
2 r 2500
{
2028 ihaka 2501
    BBOX bbox;
2502
    FontType prevfont = SetFont(ItalicFont);
2503
    bbox = RenderElement(CADR(expr), draw);
2504
    SetFont(prevfont);
2505
    return bbox;
2 r 2506
}
2507
 
2028 ihaka 2508
/*----------------------------------------------------------------------
2509
 *
2510
 *  Code for Plain (i.e. Roman) Expressions
2511
 *
2512
 */
2 r 2513
 
2028 ihaka 2514
static int PlainAtom(SEXP expr)
2 r 2515
{
2028 ihaka 2516
    return NameAtom(expr) &&
2517
	NameMatch(expr, "plain");
2 r 2518
}
2519
 
2028 ihaka 2520
static BBOX RenderPlain(SEXP expr, int draw)
2 r 2521
{
2028 ihaka 2522
    BBOX bbox;
2523
    int prevfont = SetFont(PlainFont);
2524
    bbox = RenderElement(CADR(expr), draw);
2525
    SetFont(prevfont);
2526
    return bbox;
2 r 2527
}
2528
 
2028 ihaka 2529
/*----------------------------------------------------------------------
2530
 *
2531
 *  Code for Bold Italic Expressions
2532
 *
2533
 */
2 r 2534
 
2028 ihaka 2535
static int BoldItalicAtom(SEXP expr)
2 r 2536
{
2028 ihaka 2537
    return NameAtom(expr) &&
2538
	(NameMatch(expr, "bolditalic") || NameMatch(expr, "boldmath"));
2 r 2539
}
2540
 
2028 ihaka 2541
static BBOX RenderBoldItalic(SEXP expr, int draw)
2 r 2542
{
2028 ihaka 2543
    BBOX bbox;
2544
    int prevfont = SetFont(BoldItalicFont);
2545
    bbox = RenderElement(CADR(expr), draw);
2546
    SetFont(prevfont);
2547
    return bbox;
2 r 2548
}
2549
 
2028 ihaka 2550
/*----------------------------------------------------------------------
2551
 *
2552
 *  Code for Styles
2553
 *
2554
 */
2 r 2555
 
2028 ihaka 2556
static int StyleAtom(SEXP expr)
2 r 2557
{
2028 ihaka 2558
    return (NameAtom(expr) &&
2559
	    (NameMatch(expr, "displaystyle") ||
2560
	     NameMatch(expr, "textstyle")    ||
2561
	     NameMatch(expr, "scriptstyle")   ||
2562
	     NameMatch(expr, "scriptscriptstyle")));
2 r 2563
}
2564
 
2028 ihaka 2565
static BBOX RenderStyle(SEXP expr, int draw)
2 r 2566
{
2028 ihaka 2567
    STYLE prevstyle = GetStyle();
2568
    BBOX bbox;
2122 maechler 2569
    if (NameMatch(CAR(expr), "displaystyle"))
2028 ihaka 2570
	SetStyle(STYLE_D);
2122 maechler 2571
    else if (NameMatch(CAR(expr), "textstyle"))
2028 ihaka 2572
	SetStyle(STYLE_T);
2122 maechler 2573
    else if (NameMatch(CAR(expr), "scriptstyle"))
2028 ihaka 2574
	SetStyle(STYLE_S);
2122 maechler 2575
    else if (NameMatch(CAR(expr), "scriptscriptstyle"))
2028 ihaka 2576
	SetStyle(STYLE_SS);
2577
    bbox = RenderElement(CADR(expr), draw);
2578
    SetStyle(prevstyle);
2579
    return bbox;
2 r 2580
}
2581
 
2028 ihaka 2582
/*----------------------------------------------------------------------
2583
 *
2584
 *  Code for Phantom Expressions
2585
 *
2586
 */
2 r 2587
 
2028 ihaka 2588
static int PhantomAtom(SEXP expr)
2 r 2589
{
2028 ihaka 2590
    return (NameAtom(expr) &&
2591
	    (NameMatch(expr, "phantom") ||
2592
	     NameMatch(expr, "vphantom")));
2 r 2593
}
2594
 
2028 ihaka 2595
static BBOX RenderPhantom(SEXP expr, int draw)
2 r 2596
{
2028 ihaka 2597
    BBOX bbox = RenderElement(CADR(expr), 0);
2598
    if (NameMatch(CAR(expr), "vphantom")) {
2599
	bboxWidth(bbox) = 0;
2600
	bboxItalic(bbox) = 0;
2601
    }
2602
    else RenderGap(bboxWidth(bbox), 0);
2603
    return bbox;
2 r 2604
}
2605
 
2028 ihaka 2606
/*----------------------------------------------------------------------
2607
 *
2608
 *  Code for Concatenate Expressions
2609
 *
2610
 */
2 r 2611
 
2028 ihaka 2612
static int ConcatenateAtom(SEXP expr)
2 r 2613
{
2028 ihaka 2614
    return NameAtom(expr) && NameMatch(expr, "paste");
2 r 2615
}
2616
 
2028 ihaka 2617
static BBOX RenderConcatenate(SEXP expr, int draw)
2 r 2618
{
2028 ihaka 2619
    BBOX bbox;
2620
    int i, n;
2 r 2621
 
2028 ihaka 2622
    expr = CDR(expr);
2623
    n = length(expr);
2 r 2624
 
2028 ihaka 2625
    for (i = 0; i < n; i++) {
2626
	bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw));
2627
	if (i != n - 1)
2628
	    bbox = RenderItalicCorr(bbox, draw);
2629
	expr = CDR(expr);
2630
    }
2631
    return bbox;
2 r 2632
}
2633
 
2028 ihaka 2634
/*----------------------------------------------------------------------
2635
 *
2636
 *  Code for Comma-Separated Lists
2637
 *
2638
 */
2 r 2639
 
2028 ihaka 2640
static BBOX RenderCommaList(SEXP expr, int draw)
2 r 2641
{
2028 ihaka 2642
    BBOX bbox = NullBBox();
2643
    double small = 0.4 * ThinSpace();
2644
    int i, n;
2645
    n = length(expr);
2646
    for (i = 0; i < n; i++) {
2647
	if (NameAtom(CAR(expr)) && NameMatch(CAR(expr), "...")) {
2648
	    if (i > 0) {
2649
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw));
2650
#ifdef OLD
2651
		bbox = CombineBBoxes(bbox, RenderGap(small, draw));
2652
#else
2653
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw));
2654
#endif
2655
	    }
2656
	    bbox = CombineBBoxes(bbox, RenderSymbolChar(S_ELLIPSIS, draw));
2657
	    bbox = CombineBBoxes(bbox, RenderGap(small, draw));
2658
	}
2659
	else {
2660
	    if (i > 0) {
2661
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_COMMA, draw));
2662
		bbox = CombineBBoxes(bbox, RenderSymbolChar(S_SPACE, draw));
2663
	    }
2664
	    bbox = CombineBBoxes(bbox, RenderElement(CAR(expr), draw));
2665
	}
2666
	expr = CDR(expr);
2667
    }
2668
    return bbox;
2 r 2669
}
2670
 
2028 ihaka 2671
/*----------------------------------------------------------------------
2672
 *
2673
 *  Code for General Expressions
2674
 *
2675
 */
2 r 2676
 
2028 ihaka 2677
static BBOX RenderExpression(SEXP expr, int draw)
2 r 2678
{
2028 ihaka 2679
    BBOX bbox;
2680
    if (NameAtom(CAR(expr)))
2681
	bbox = RenderSymbolString(CAR(expr), draw);
2682
    else
2683
	bbox = RenderElement(CAR(expr), draw);
2684
    bbox = RenderItalicCorr(bbox, draw);
2105 ihaka 2685
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENLEFT, draw));
2028 ihaka 2686
    bbox = CombineBBoxes(bbox, RenderCommaList(CDR(expr), draw));
2687
    bbox = RenderItalicCorr(bbox, draw);
2105 ihaka 2688
    bbox = CombineBBoxes(bbox, RenderDelimiter(S_PARENRIGHT, draw));
2028 ihaka 2689
    return bbox;
2 r 2690
}
2691
 
2028 ihaka 2692
/*----------------------------------------------------------------------
2693
 *
2694
 *  Code for Comma Separated List Expressions
2695
 *
2696
 */
2 r 2697
 
2028 ihaka 2698
static int ListAtom(SEXP expr)
2 r 2699
{
2028 ihaka 2700
    return NameAtom(expr) && NameMatch(expr, "list");
2 r 2701
}
2702
 
2028 ihaka 2703
static BBOX RenderList(SEXP expr, int draw)
2 r 2704
{
2028 ihaka 2705
    return RenderCommaList(CDR(expr), draw);
2 r 2706
}
2707
 
1839 ihaka 2708
/* Dispatching procedure which determines nature of expression. */
2 r 2709
 
2028 ihaka 2710
 
2711
static BBOX RenderFormula(SEXP expr, int draw)
2 r 2712
{
1839 ihaka 2713
    SEXP head = CAR(expr);
2 r 2714
 
2028 ihaka 2715
    if (SpaceAtom(head))
2716
	return RenderSpace(expr, draw);
2717
    else if (BinAtom(head))
2718
	return RenderBin(expr, draw);
2719
    else if (SuperAtom(head))
2720
	return RenderSup(expr, draw);
2721
    else if (SubAtom(head))
2722
	return RenderSub(expr, draw);
2723
    else if (WideTildeAtom(head))
2724
	return RenderWideTilde(expr, draw);
2725
    else if (WideHatAtom(head))
2726
	return RenderWideHat(expr, draw);
2727
    else if (BarAtom(head))
2728
	return RenderBar(expr, draw);
2729
    else if (AccentAtom(head))
2730
	return RenderAccent(expr, draw);
2731
    else if (OverAtom(head))
2732
	return RenderOver(expr, draw);
2733
    else if (AtopAtom(head))
2734
	return RenderAtop(expr, draw);
2735
    else if (ParenAtom(head))
2736
	return RenderParen(expr, draw);
2737
    else if (BGroupAtom(head))
2738
	return RenderBGroup(expr, draw);
2739
    else if (GroupAtom(head))
2740
	return RenderGroup(expr, draw);
2741
    else if (IntAtom(head))
3475 pd 2742
	return RenderInt(expr, draw);
2028 ihaka 2743
    else if (OpAtom(head))
2744
	return RenderOp(expr, draw);
2745
    else if (RadicalAtom(head))
2746
	return RenderRadical(expr, draw);
2747
    else if (AbsAtom(head))
2748
	return RenderAbs(expr, draw);
2749
    else if (CurlyAtom(head))
2750
	return RenderCurly(expr, draw);
2751
    else if (RelAtom(head))
2752
	return RenderRel(expr, draw);
2753
    else if (BoldAtom(head))
2754
	return RenderBold(expr, draw);
2755
    else if (ItalicAtom(head))
2756
	return RenderItalic(expr, draw);
2757
    else if (PlainAtom(head))
2758
	return RenderPlain(expr, draw);
2759
    else if (BoldItalicAtom(head))
2760
	return RenderBoldItalic(expr, draw);
2761
    else if (StyleAtom(head))
2762
	return RenderStyle(expr, draw);
2763
    else if (PhantomAtom(head))
2764
	return RenderPhantom(expr, draw);
2765
    else if (ConcatenateAtom(head))
2766
	return RenderConcatenate(expr, draw);
2767
    else if (ListAtom(head))
2768
	return RenderList(expr, draw);
1839 ihaka 2769
    else
2028 ihaka 2770
	return RenderExpression(expr, draw);
2 r 2771
}
2772
 
2773
 
2028 ihaka 2774
/* Dispatch on whether atom (symbol, string, number, ...) */
2775
/* or formula (some sort of expression) */
2 r 2776
 
2028 ihaka 2777
static BBOX RenderElement(SEXP expr, int draw)
2778
{
2779
    if (FormulaExpression(expr))
2780
	return RenderFormula(expr, draw);
1839 ihaka 2781
    else
2028 ihaka 2782
	return RenderAtom(expr, draw);
2 r 2783
}
2784
 
2028 ihaka 2785
static BBOX RenderOffsetElement(SEXP expr, double x, double y, int draw)
2786
{
2787
    BBOX bbox;
2788
    double savedX = CurrentX;
2789
    double savedY = CurrentY;
2790
    if (draw) {
2791
	CurrentX += x;
2792
	CurrentY += y;
2793
    }
2794
    bbox = RenderElement(expr, draw);
2795
    bboxWidth(bbox) += x;
2796
    bboxHeight(bbox) += y;
2797
    bboxDepth(bbox) -= y;
2798
    CurrentX = savedX;
2799
    CurrentY = savedY;
2800
    return bbox;
2 r 2801
 
2802
}
2803
 
2028 ihaka 2804
/* Calculate width of expression */
2805
/* BBOXes are in INCHES (see MetricUnit) */
2806
 
2807
void GExpressionBBox(SEXP expr, int units, double *width,
2808
		     double *height, double *depth, DevDesc *dd)
2 r 2809
{
2679 pd 2810
    BBOX bbox;
2811
    MathDevice = dd;
2812
/* The following two lines don't look right to me, but I inserted them
2813
   because otherwise you get trouble if you calculate BBoxes without
2814
   plotting any math first... Similar problem in the next two functions
2815
	 --pd */
2816
    CurrentStyle = STYLE_D;
2817
    SetFont(PlainFont);
2818
    bbox = RenderElement(expr, 0);
2028 ihaka 2819
    *width  = bboxWidth(bbox);
2820
    *height  = bboxHeight(bbox);
2821
    *depth  = bboxDepth(bbox);
2822
    if (units != INCHES) {
2823
	*width = GConvertXUnits(*width, INCHES, units, dd);
2824
	*height = GConvertYUnits(*height, INCHES, units, dd);
2825
	*depth = GConvertYUnits(*depth, INCHES, units, dd);
2826
    }
2 r 2827
}
2828
 
581 paul 2829
double GExpressionWidth(SEXP expr, int units, DevDesc *dd)
257 paul 2830
{
2679 pd 2831
    BBOX bbox;
2832
    double width;
2833
    MathDevice = dd;
2834
    CurrentStyle = STYLE_D;
2835
    SetFont(PlainFont);
2836
    bbox = RenderElement(expr, 0);
2837
    width  = bboxWidth(bbox);
1839 ihaka 2838
    if (units == INCHES)
2028 ihaka 2839
	return width;
1839 ihaka 2840
    else
2028 ihaka 2841
	return GConvertXUnits(width, INCHES, units, dd);
257 paul 2842
}
2843
 
581 paul 2844
double GExpressionHeight(SEXP expr, int units, DevDesc *dd)
257 paul 2845
{
2679 pd 2846
    BBOX bbox;
2847
    double height;
2848
    MathDevice = dd;
2849
    CurrentStyle = STYLE_D;
2850
    SetFont(PlainFont);
2851
    bbox = RenderElement(expr, 0);
2852
    height = bboxHeight(bbox) + bboxDepth(bbox);
1839 ihaka 2853
    if (units == INCHES)
2028 ihaka 2854
	return height;
1839 ihaka 2855
    else
2028 ihaka 2856
	return GConvertYUnits(height, INCHES, units, dd);
257 paul 2857
}
2858
 
2028 ihaka 2859
/* Functions forming the R API */
2 r 2860
 
1016 maechler 2861
void GMathText(double x, double y, int coords, SEXP expr,
581 paul 2862
	       double xc, double yc, double rot, DevDesc *dd)
2 r 2863
{
2028 ihaka 2864
    BBOX bbox;
2865
    MathDevice = dd;
2866
    BaseCex = MathDevice->gp.cex;
2867
    BoxColor = name2col("pink");
2868
    TextColor = MathDevice->gp.col;
2869
    CurrentStyle = STYLE_D;
2105 ihaka 2870
    SetFont(PlainFont);
2028 ihaka 2871
    bbox = RenderElement(expr, 0);
2872
    ReferenceX = x;
2873
    ReferenceY = y;
2874
    GConvert(&ReferenceX, &ReferenceY, coords, INCHES, dd);
2875
    if (FINITE(xc))
2876
	CurrentX = ReferenceX - xc * bboxWidth(bbox);
2877
    else
2878
	CurrentX = ReferenceX;
2879
    if (FINITE(yc))
2880
	CurrentY = ReferenceY + bboxDepth(bbox)
2881
	    - yc * (bboxHeight(bbox) + bboxDepth(bbox));
2882
    else
2883
	CurrentY = ReferenceY;
2884
    CurrentAngle = rot;
2123 maechler 2885
    rot *= M_PI_half / 90 ;/* radians */
2122 maechler 2886
    CosAngle = cos(rot);
2887
    SinAngle = sin(rot);
2028 ihaka 2888
    RenderElement(expr, 1);
2 r 2889
}
2890
 
2891
 
2028 ihaka 2892
void GMMathText(SEXP str, int side, double line, int outer,
2893
		double at, int las, DevDesc *dd)
2 r 2894
{
3475 pd 2895
    int coords = 0;
1839 ihaka 2896
    double a, xadj, yadj;
2 r 2897
 
2028 ihaka 2898
    MathDevice = dd;
581 paul 2899
 
1839 ihaka 2900
    if (outer) {
2901
	switch (side) {
2902
	case 1:
2903
	    line = line + 1;
2904
	    coords = MAR1;
2028 ihaka 2905
	    a = 0;
2906
	    xadj = MathDevice->gp.adj;
2907
	    yadj = NA_REAL;
1839 ihaka 2908
	    break;
2909
	case 2:
2910
	    coords = MAR2;
2028 ihaka 2911
	    a = 90;
2912
	    xadj = MathDevice->gp.adj;
2913
	    yadj = NA_REAL;
1839 ihaka 2914
	    break;
2915
	case 3:
2916
	    coords = MAR3;
2917
	    a = 0.0;
2028 ihaka 2918
	    xadj = MathDevice->gp.adj;
2919
	    yadj = NA_REAL;
1839 ihaka 2920
	    break;
2921
	case 4:
2922
	    line = line + 1;
2923
	    coords = MAR4;
2924
	    a = 90.0;
2028 ihaka 2925
	    xadj = MathDevice->gp.adj;
2926
	    yadj = NA_REAL;
1839 ihaka 2927
	    break;
3475 pd 2928
	default: return;/* never happens */
2 r 2929
	}
1839 ihaka 2930
	GMathText(at, line, coords, str, xadj, yadj, a, dd);
2931
    }
2932
    else {
2933
	switch (side) {
2934
	case 1:
3475 pd 2935
	    if (las == 2 || las == 3) {/* perpendicular */
1839 ihaka 2936
		at = at - GConvertXUnits(dd->gp.yLineBias,
2937
					 LINES, USER, dd);
2938
		line = line + dd->gp.yLineBias;
2939
		a = 90.0;
2940
		xadj = 1.0;
2941
		yadj = 0.5;
2942
	    }
2943
	    else {
2944
		line = line + 1 - dd->gp.yLineBias;
2945
		a = 0.0;
2028 ihaka 2946
		xadj = MathDevice->gp.adj;
2947
		yadj = NA_REAL;
1839 ihaka 2948
	    }
2949
	    coords = MAR1;
2950
	    break;
2951
	case 2:
2952
	    if (las == 1 || las == 2) {
2953
		at = at + GConvertYUnits(dd->gp.yLineBias,
2954
					 LINES, USER, dd);
2955
		line = line + dd->gp.yLineBias;
2956
		a = 0.0;
2957
		xadj = 1.0;
2958
		yadj = 0.5;
2959
	    }
2960
	    else {
2961
		line = line + dd->gp.yLineBias;
2962
		a = 90.0;
2028 ihaka 2963
		xadj = MathDevice->gp.adj;
2964
		yadj = NA_REAL;
1839 ihaka 2965
	    }
2966
	    coords = MAR2;
2967
	    break;
2968
	case 3:
3475 pd 2969
	    if (las == 2 || las == 3) {/* perpendicular */
1839 ihaka 2970
		at = at - GConvertXUnits(dd->gp.yLineBias,
2971
					 LINES, USER, dd);
2972
		line = line + dd->gp.yLineBias;
2973
		a = 90.0;
2974
		xadj = 0.0;
2975
		yadj = 0.5;
2976
	    }
2977
	    else {
2978
		line = line + dd->gp.yLineBias;
2979
		a = 0.0;
2028 ihaka 2980
		xadj = MathDevice->gp.adj;
2981
		yadj = NA_REAL;
1839 ihaka 2982
	    }
2983
	    coords = MAR3;
2984
	    break;
2985
	case 4:
2986
	    if (las == 1 || las == 2) {
2987
		at = at + GConvertYUnits(dd->gp.yLineBias,
2988
					 LINES, USER, dd);
2989
		line = line + dd->gp.yLineBias;
2990
		a = 0.0;
2991
		xadj = 0.0;
2992
		yadj = 0.5;
2993
	    }
2994
	    else {
2995
		line = line + 1 - dd->gp.yLineBias;
2996
		a = 90.0;
2028 ihaka 2997
		xadj = MathDevice->gp.adj;
2998
		yadj = NA_REAL;
1839 ihaka 2999
	    }
3000
	    coords = MAR4;
3001
	    break;
3475 pd 3002
	default: return;/* never happens */
2 r 3003
	}
1839 ihaka 3004
	GMathText(at, line, coords, str, xadj, yadj, a, dd);
3005
    }
2 r 3006
}