The R Project SVN R

Rev

Rev 1926 | Rev 2105 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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