The R Project SVN R

Rev

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