The R Project SVN R

Rev

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