The R Project SVN R

Rev

Rev 257 | Rev 581 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 r 1
/*
2
 *  R : A Computer Langage for Statistical Data Analysis
3
 *  Copyright (C) 1995, 1996, 1997 Robert Gentleman and Ross Ihaka
4
 *
5
 *  This source code module:
6
 *  Copyright (C) 1997 Paul Murrell and Ross Ihaka
7
 *
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
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  (at your option) any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License
19
 *  along with this program; if not, write to the Free Software
20
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
 */
22
 
23
#include "Mathlib.h"
24
#include "Graphics.h"
25
#include "Defn.h"
26
#ifdef max
27
#undef max
28
#endif
29
#ifdef Unix
30
 
31
		/* return maximum of two doubles */
32
 
33
static double max(double x, double y)
34
{
35
	if (x > y) return x;
36
	else return y;
37
}
38
 
39
		/* determine match between symbol name and string */
40
 
41
static int symbolMatch(SEXP expr, char *aString)
42
{
43
	return !strcmp(CHAR(PRINTNAME(expr)), aString);
44
}
45
 
46
		/* code to determine the ascii code corresponding */
47
		/* to an element of a mathematical expression */
48
 
49
static int hatAscii()
50
{
51
	return 94;
52
}
53
 
54
static int tildeAscii()
55
{
56
	return 126;
57
}
58
 
59
static int accentAscii(SEXP expr)
60
{
61
	int result = 0;
62
 
63
	if (symbolMatch(expr, "hat"))
64
		result = hatAscii();
65
	else if (symbolMatch(expr, "tilde"))
66
		result = tildeAscii();
67
 
68
	return result;
69
}
70
 
71
static int operatorAscii(SEXP expr)
72
{
73
	int result = 0;
74
 
75
	if (symbolMatch(expr, "sum"))
76
		result = 229;
77
	else if (symbolMatch(expr, "integral"))
78
		result = 242;
79
	else if (symbolMatch(expr, "product"))
80
		result = 213;
81
 
82
	return result;
83
}
84
 
85
static int integralAscii(int section)
86
{
87
  if (section == 1)
88
    return 243;
89
  else if (section == 2)
90
    return 244;
91
  else 
92
    return 245;
93
}
94
 
95
static int groupOpenAscii()
96
{
97
	return 40;
98
}
99
 
100
static int groupCloseAscii()
101
{
102
	return 41;
103
}
104
 
105
static int commaAscii()
106
{
107
	return 44;
108
}
109
 
110
static int spaceAscii()
111
{
112
	return 32;
113
}
114
 
115
static int radicalAscii()
116
{
117
	return 214;
118
}
119
 
120
static int radicalExAscii()
121
{
122
	return 96;
123
}
124
 
125
static struct {
126
	char *name;
127
	int code;
128
} GreekTable[] = {
129
 
130
	"Alpha", 65,
131
	"Beta", 66,
132
	"Chi", 67,
133
	"Delta", 68,
134
	"Epsilon", 69,
135
	"Phi", 70,
136
	"Gamma", 71,
137
	"Eta", 72,
138
	"Iota", 73,
139
	"Phi1", 74,
140
	"Kappa", 75,
141
	"Lambda", 76,
142
	"Mu", 77,
143
	"Nu", 78,
144
	"Omicron", 79,
145
	"Pi", 80,
146
	"Theta", 81,
147
	"Rho", 82,
148
	"Sigma", 83,
149
	"Tau", 84,
150
	"Upsilon", 85,
151
	"sigma1", 86,
152
	"Omega", 87,
153
	"Xi", 88,
154
	"Psi", 89,
155
	"Zeta", 90,
156
 
157
	"alpha", 97,
158
	"beta", 98,
159
	"chi", 99,
160
	"delta", 100,
161
	"epsilon", 101,
162
	"phi", 102,
163
	"gamma", 103,
164
	"eta", 104,
165
	"iota", 105,
166
	"phi1", 106,
167
	"kappa", 107,
168
	"lambda", 108,
169
	"mu", 109,
170
	"nu", 110,
171
	"omicron", 111,
172
	"pi", 112,
173
	"theta", 113,
174
	"rho", 114,
175
	"sigma", 115,
176
	"tau", 116,
177
	"upsilon", 117,
178
	"omega1", 118,
179
	"omega", 119,
180
	"xi", 120,
181
	"psi", 121,
182
	"zeta", 122,
183
 
184
	NULL, 0,
185
};
186
 
187
static int greekAscii(SEXP expr)
188
{
189
	int i;
190
 
191
	for (i = 0; GreekTable[i].code; i++)
192
		if (symbolMatch(expr, GreekTable[i].name))
193
			return GreekTable[i].code;
194
	return 0;
195
}
196
 
197
static int relAscii() { return 61; }
198
 
199
	/* initialisation code for mathematical notation */
200
 
201
static double ratioScale = 0.8;
202
static double scriptScale = 0.65;
203
static int ratioDepth = 0;
204
static int metricUnit = 3;
205
 
206
static SEXP plusSymbol;
207
static SEXP minusSymbol;
208
static SEXP timesSymbol;
209
static SEXP divideSymbol;
210
static SEXP equalSymbol;
211
static SEXP superSymbol;
212
static SEXP subSymbol;
213
static SEXP groupSymbol;
214
 
215
static void initFormulaSymbols()
216
{
217
	plusSymbol = install("+");
218
	minusSymbol = install("-");
219
	timesSymbol = install("*");
220
	divideSymbol = install("/");
221
	equalSymbol = install("==");
222
	superSymbol = install("^");
223
	subSymbol = install("[");
224
	groupSymbol = install("(");
225
}
226
 
227
	/* code to determine the nature of an expression */
228
 
229
static int formulaExpression(SEXP expr)
230
{
231
	return (TYPEOF(expr) == LANGSXP);
232
}
233
 
234
static int symbolAtom(SEXP expr)
235
{
236
	return (TYPEOF(expr) == SYMSXP);
237
}
238
 
239
static int numberAtom(SEXP expr)
240
{
241
	return (TYPEOF(expr) == REALSXP) ||
242
	    (TYPEOF(expr) == INTSXP) ||
243
	    (TYPEOF(expr) == CPLXSXP);
244
}
245
 
246
static int stringAtom(SEXP expr)
247
{
248
	return (TYPEOF(expr) == STRSXP);
249
}
250
 
251
static int binAtom(SEXP expr)
252
{
253
	int result = symbolAtom(expr) &&
254
	((expr == plusSymbol) ||
255
	 (expr == minusSymbol) ||
256
	 (expr == timesSymbol) ||
257
	 (expr == divideSymbol));
258
	return result;
259
}
260
 
261
static int relAtom(SEXP expr)
262
{
263
	return symbolAtom(expr) &&
264
	    (expr == equalSymbol);
265
}
266
 
267
static int multiplicationOperator(SEXP expr)
268
{
269
	return binAtom(expr) &&
270
	    (expr == timesSymbol);
271
}
272
 
273
static int superAtom(SEXP expr)
274
{
275
	return symbolAtom(expr) &&
276
	    (expr == superSymbol);
277
}
278
 
279
static int subAtom(SEXP expr)
280
{
281
	return symbolAtom(expr) &&
282
	    (expr == subSymbol);
283
}
284
 
285
static int hatAtom(SEXP expr)
286
{
287
	return symbolMatch(expr, "hat");
288
}
289
 
290
static int barAtom(SEXP expr)
291
{
292
	return symbolMatch(expr, "bar");
293
}
294
 
295
static int accentAtom(SEXP expr)
296
{
297
	return symbolAtom(expr) &&
298
	    (hatAtom(expr) || barAtom(expr) ||
299
	     symbolMatch(expr, "tilde"));
300
}
301
 
302
static int fractionAtom(SEXP expr)
303
{
304
	return symbolAtom(expr) &&
254 paul 305
	    (symbolMatch(expr, "over") || symbolMatch(expr, "frac"));
2 r 306
}
307
 
308
static int groupAtom(SEXP expr)
309
{
310
	return symbolAtom(expr) && (expr == groupSymbol);
311
}
312
 
313
static int operatorAtom(SEXP expr)
314
{
315
	return symbolAtom(expr) &&
316
	    (symbolMatch(expr, "sum") ||
317
	     symbolMatch(expr, "integral") ||
318
	     symbolMatch(expr, "product"));
319
}
320
 
321
static int integralOperator(SEXP expr)
322
{
323
  return symbolAtom(expr) && symbolMatch(expr, "integral");
324
}
325
 
326
static int radicalAtom(SEXP expr)
327
{
328
	return symbolAtom(expr) &&
329
	    (symbolMatch(expr, "root") || 
330
	     symbolMatch(expr, "sqrt"));
331
}
332
 
333
static int absAtom(SEXP expr)
334
{
335
	return symbolAtom(expr) && symbolMatch(expr, "abs");
336
}
337
 
338
static int curlyAtom(SEXP expr)
339
{
340
	return symbolAtom(expr) && symbolMatch(expr, "{");
341
}
342
 
343
static int boldAtom(SEXP expr)
344
{
345
	return symbolAtom(expr) && symbolMatch(expr, "bold");
346
}
347
 
348
static int italicAtom(SEXP expr)
349
{
350
	return symbolAtom(expr) && symbolMatch(expr, "italic");
351
}
352
 
353
static int plainAtom(SEXP expr)
354
{
355
	return symbolAtom(expr) && symbolMatch(expr, "plain");
356
}
357
 
358
static int boldItalicAtom(SEXP expr)
359
{
360
	return symbolAtom(expr) && symbolMatch(expr, "bolditalic");
361
}
362
 
363
static int italicExpression(SEXP expr)
364
{
365
	return formulaExpression(expr) &&
366
	       (italicAtom(CAR(expr)) || boldItalicAtom(CAR(expr)));
367
}
368
 
369
static int nonItalicExpression(SEXP expr)
370
{
371
	return formulaExpression(expr) &&
372
	       (boldAtom(CAR(expr)) || plainAtom(CAR(expr)));
373
}
374
 
375
static int concatenateAtom(SEXP expr)
376
{
377
	return symbolAtom(expr) && symbolMatch(expr, "paste");
378
}
379
 
380
static int greekSymbol(SEXP expr)
381
{
382
	int i;
383
	if (symbolAtom(expr)) {
384
		for (i = 0; GreekTable[i].code; i++)
385
			if (symbolMatch(expr, GreekTable[i].name))
386
				return 1;
387
	}
388
	return 0;
389
}
390
 
391
		/* code to determine a font from the */
392
		/* nature of the expression */
393
 
394
static int currentFont = 3;
395
 
396
static int getFont() { return currentFont; }
397
 
398
static void setFont(font) { currentFont = font; }
399
 
400
static void boldFont() { setFont(2); }
401
static void italicFont() { setFont(3); }
402
static void plainFont() { setFont(1); }
403
static void boldItalicFont() { setFont(4); }
404
 
405
static int isItalic() { return (getFont() == 3 || getFont() == 4); }
406
 
407
static int atomFontFace(SEXP expr)
408
{
409
	int fontFace = 1;
410
	if (symbolAtom(expr)) {
411
		if (greekSymbol(expr) ||
412
		    binAtom(expr) ||
413
		    relAtom(expr) ||
414
		    groupAtom(expr) ||
415
		    operatorAtom(expr) ||
416
		    radicalAtom(expr))
417
			fontFace = 5;
418
		else
419
#ifdef OLD
420
			fontFace = 3;
421
#else
422
			fontFace = getFont();
423
#endif
424
	}
425
	return fontFace;
426
}
427
 
428
	/* a forward declaration */
429
static double fontHeight();
430
 
431
	/* some forward declarations */
432
 
433
typedef struct {
434
	double height;
435
	double depth;
436
	double width;
437
} BBOX;
438
 
439
static double bboxHeight(BBOX bbox)
440
{
441
	return bbox.height;
442
}
443
static double bboxDepth(BBOX bbox)
444
{
445
	return bbox.depth;
446
}
447
static double bboxWidth(BBOX bbox)
448
{
449
	return bbox.width;
450
}
451
static BBOX asciiBBox(int ascii);
452
static BBOX elementBBox(SEXP expr);
453
static void drawElement(SEXP expr);
454
 
455
 
456
	/* code to determine superscript offsets, etc ... */
457
 
458
	/* these "twiddle factors" are given as  */
459
	/* proportions of the current font height */
460
	/* NOTE that metric information is obtained */
461
	/* in INCHES so that the information will */
462
	/* be useful for rotated math.text */
463
 
464
 
465
static float SuperDrop = 0.3;
466
static float Superscript = 0.3;
467
static float SubDrop = 0.1;
468
static float Subscript = -0.3;
469
static float LineWidth = 0.05;
470
 
471
static float CustomAccentGap = 0.2;
472
static float CustomHatHeight = 0.3;
473
static float CustomRadicalWidth = 0.6;
474
static float CustomRadicalSpace = 0.1;
475
static float CustomRadicalGap = 0.2;
476
static float AbsSpace = 0.2;
477
static float OperatorSpace[] = { 0.1, 0.15, 0.2, 0.6, 0.1 };
478
 
479
static double fontHeight()
480
{
481
	double height, depth, width;
482
	GMetricInfo(0, &height, &depth, &width, metricUnit);
483
	return height + depth;
484
}
485
 
486
static double xHeight()
487
{
488
	int x = 'x';
489
	double xheight, depth, width;
490
	GMetricInfo(x, &xheight, &depth, &width, metricUnit);
491
	return xheight;
492
}
493
 
494
static double axisHeight()
495
{
496
	int plus = '+';
497
	double plusHeight, depth, width;
498
	GMetricInfo(plus, &plusHeight, &depth, &width, metricUnit);
499
	return 0.5 * plusHeight;
500
}
501
 
502
static double superscriptDrop()
503
{
504
	return SuperDrop * fontHeight();
505
}
506
static double subscriptDrop()
507
{
508
	return SubDrop * fontHeight();
509
}
510
static double superscript()
511
{
512
	return Superscript * fontHeight();
513
}
514
static double subscript()
515
{
516
	return Subscript * fontHeight();
517
}
518
static double lineWidth()
519
{
520
	return LineWidth * fontHeight();
521
}
522
static double numeratorShift()
523
{
524
	return axisHeight() + 3 * lineWidth();
525
}
526
static double denominatorShift()
527
{
528
	return axisHeight() - 3 * lineWidth() - xHeight();
529
}
530
static double radicalDrop()
531
{
532
	return 1.25 * lineWidth();
533
}
534
static double customAccentGap()
535
{
536
	return CustomAccentGap * fontHeight();
537
}
538
static double customHatHeight()
539
{
540
	return CustomHatHeight * fontHeight();
541
}
542
static double customRadicalWidth()
543
{
544
	return CustomRadicalWidth * fontHeight();
545
}
546
static double customRadicalSpace()
547
{
548
	return CustomRadicalSpace * fontHeight();
549
}
550
static double customRadicalGap()
551
{
552
	return CustomRadicalGap * fontHeight();
553
}
554
static double absSpace()
555
{
556
	return AbsSpace * fontHeight();
557
}
558
static double operatorSpace(int i)
559
{
560
  return OperatorSpace[i] * fontHeight();
561
}
562
 
563
 
564
	/* should only be called when font=5 (symbol) */
565
 
566
static double radicalExWidth()
567
{
568
	int radicalEx = 96;
569
	double height, depth, REWidth;
570
	GMetricInfo(radicalEx, &height, &depth, &REWidth, metricUnit);
571
	return REWidth;
572
}
573
 
574
static double superscriptShift(SEXP body, SEXP sup)
575
{
576
	BBOX bodyBBox = elementBBox(body);
577
	BBOX superscriptBBox;
578
	float cexSaved = GP->cex;
579
	double temp1 = bboxHeight(bodyBBox) - superscriptDrop();
580
	double temp2 = superscript();
581
	double temp3;
582
 
583
	GP->cex = GP->cex * scriptScale;
584
	superscriptBBox = elementBBox(sup);
585
	GP->cex = cexSaved;
586
	temp3 = bboxDepth(superscriptBBox) + 0.25 * xHeight();
587
 
588
	return max(temp1, max(temp2, temp3));
589
}
590
 
591
static double subscriptShift(SEXP body, SEXP sub, int subOnly)
592
{
593
	BBOX bodyBBox = elementBBox(body);
594
	BBOX subscriptBBox;
595
	float cexSaved = GP->cex;
596
	double temp1 = bboxDepth(bodyBBox) + subscriptDrop();
597
	double temp2 = subscript();
598
	double temp3;
599
 
600
	GP->cex = GP->cex * scriptScale;
601
	subscriptBBox = elementBBox(sub);
602
	GP->cex = cexSaved;
603
	temp3 = bboxHeight(subscriptBBox) - (4 * xHeight() / 5);
604
 
605
	if (subOnly)
606
		return max(temp1, max(temp2, temp3));
607
	else
608
		return max(temp1, temp2);
609
}
610
 
611
static void supsubShift(SEXP body, SEXP sup, SEXP sub,
612
			double *supShift, double *subShift)
613
{
614
	BBOX superscriptBBox, subscriptBBox;
615
	float cexSaved = GP->cex;
616
	double temp1, temp2;
617
 
618
	GP->cex = GP->cex * scriptScale;
619
	superscriptBBox = elementBBox(sup);
620
	subscriptBBox = elementBBox(sub);
621
	GP->cex = cexSaved;
622
	*supShift = superscriptShift(body, sup);
623
	*subShift = subscriptShift(body, sub, 0);
624
 
625
	temp1 = (*supShift - bboxDepth(superscriptBBox)) -
626
	    (bboxHeight(subscriptBBox) - *subShift);
627
	if (temp1 < (4 * lineWidth()))
628
		*subShift = bboxHeight(subscriptBBox) -
629
		    *supShift +
630
		    bboxDepth(superscriptBBox) +
631
		    (4 * lineWidth());
632
 
633
	temp2 = (4 * xHeight() / 5) -
634
	    (*supShift - bboxDepth(superscriptBBox));
635
	if (temp2 > 0) {
636
		*supShift = *supShift + temp2;
637
		*subShift = *subShift - temp2;
638
	}
639
}
640
 
641
static double accentVShift(SEXP body)
642
{
643
	double temp = xHeight();
644
	double bodyHeight = bboxHeight(elementBBox(body));
645
 
646
	if (bodyHeight > temp)
647
		return bodyHeight - temp;
648
	else
649
		return 0;
650
}
651
 
652
static double accentHShift(SEXP body, SEXP accent)
653
{
654
	return (bboxWidth(elementBBox(body)) -
655
		bboxWidth(elementBBox(accent))) / 2;
656
}
657
 
658
static double numeratorVShift(SEXP num)
659
{
660
	BBOX numBBox;
661
	float cexSaved = GP->cex;
662
	double theShift, theClearance, minClearance;
663
 
664
	GP->cex = GP->cex * scriptScale;
665
	numBBox = elementBBox(num);
666
	GP->cex = cexSaved;
667
 
668
	theShift = numeratorShift();
669
	theClearance = numeratorShift() - bboxDepth(numBBox) -
670
	    (axisHeight() + 0.5 * lineWidth());
671
	minClearance = 3 * lineWidth();
672
 
673
	if (theClearance < minClearance)
674
		theShift += minClearance - theClearance;
675
 
676
	return theShift;
677
}
678
 
679
/* RATIO */
680
static double denominatorVShift(SEXP denom)
681
{
682
	BBOX denomBBox;
683
	float cexSaved = GP->cex;
684
	double theShift, theClearance, minClearance;
685
 
686
#ifdef OLD
687
	GP->cex = GP->cex * scriptScale;
688
#else
689
	GP->cex = GP->cex * ratioScale;
690
#endif
691
	denomBBox = elementBBox(denom);
692
#ifdef OLD
693
	GP->cex = cexSaved;
694
#else
695
	GP->cex = cexSaved;
696
#endif
697
 
698
	theShift = denominatorShift();
699
	theClearance = axisHeight() - 0.5 * lineWidth() -
700
	    (bboxHeight(denomBBox) - denominatorShift());
701
	minClearance = 3 * lineWidth();
702
 
703
	if (theClearance < minClearance)
704
		theShift += minClearance - theClearance;
705
 
706
	return theShift;
707
}
708
 
709
/* RATIO */
710
static double fractionWidth(SEXP num, SEXP denom)
711
{
712
	BBOX numBBox;
713
	BBOX denomBBox;
714
	float cexSaved = GP->cex;
715
	double temp1, temp2;
716
 
717
#ifdef OLD
718
	GP->cex = GP->cex * scriptScale;
719
#else
720
	GP->cex = GP->cex * ratioScale;
721
#endif
722
	numBBox = elementBBox(num);
723
	denomBBox = elementBBox(denom);
724
#ifdef OLD
725
	GP->cex = cexSaved;
726
#else
727
	GP->cex = cexSaved;
728
#endif
729
	temp1 = bboxWidth(numBBox);
730
	temp2 = bboxWidth(denomBBox);
731
 
732
	return max(temp1, temp2);
733
}
734
 
735
/* RATIO */
736
static void numdenomHShift(SEXP num, SEXP denom,
737
			   double *numShift, double *denomShift)
738
{
739
	BBOX numBBox;
740
	BBOX denomBBox;
741
	float cexSaved = GP->cex;
742
	double temp1, temp2;
743
 
744
#ifdef OLD
745
	GP->cex = GP->cex * scriptScale;
746
#else
747
	GP->cex = GP->cex * ratioScale;
748
#endif
749
	numBBox = elementBBox(num);
750
	denomBBox = elementBBox(denom);
751
#ifdef OLD
752
	GP->cex = cexSaved;
753
#else
754
	GP->cex = cexSaved;
755
#endif
756
	temp1 = bboxWidth(numBBox);
757
	temp2 = bboxWidth(denomBBox);
758
 
759
	if (temp1 > temp2) {
760
		*numShift = 0;
761
		*denomShift = (temp1 - temp2) / 2;
762
	}
763
	else {
764
		*numShift = (temp2 - temp1) / 2;
765
		*denomShift = 0;
766
	}
767
}
768
 
769
static int normalRadical(SEXP body)
770
{
771
	BBOX bodyBBox = elementBBox(body);
772
	BBOX radicalBBox = asciiBBox(radicalAscii());
773
 
774
	return ((bboxHeight(bodyBBox) + radicalDrop())
775
		<= bboxHeight(radicalBBox)) &&
776
	    (bboxDepth(bodyBBox) <= bboxDepth(radicalBBox));
777
}
778
 
779
static double radicalVShift(SEXP body)
780
{
781
	BBOX bodyBBox = elementBBox(body);
782
	return bboxHeight(bodyBBox) + radicalDrop();
783
}
784
 
785
 
786
static BBOX theOperatorBBox(SEXP operator);
787
 
788
static BBOX operatorLimitBBox(SEXP operator);
789
 
790
static double operatorLowerShift(SEXP operator, SEXP lower)
791
{
792
  BBOX opBBox = theOperatorBBox(operator);
793
  BBOX lowerBBox;
794
  double lowerHeight;
795
  double spacing2 = operatorSpace(1);
796
  double spacing4 = operatorSpace(3);
797
 
798
  lowerBBox = operatorLimitBBox(lower);
799
  lowerHeight = bboxHeight(lowerBBox);
800
  if (spacing2 > (spacing4 - lowerHeight))
801
    return bboxDepth(opBBox) + spacing2 + lowerHeight;
802
  else
803
    return bboxDepth(opBBox) + spacing4;
804
}
805
 
806
static double operatorUpperShift(SEXP operator, SEXP upper)
807
{
808
  BBOX opBBox = theOperatorBBox(operator);
809
  BBOX upperBBox;
810
  double upperDepth;
811
  double spacing1 = operatorSpace(0);
812
  double spacing3 = operatorSpace(2);
813
 
814
  upperBBox = operatorLimitBBox(upper);
815
  upperDepth = bboxDepth(upperBBox);
816
  if (spacing1 > (spacing3 - upperDepth))
817
    return bboxHeight(opBBox) + spacing1 + upperDepth;
818
  else
819
    return bboxHeight(opBBox) + spacing3;
820
}
821
 
822
static double operatorLowerHShift(SEXP operator, SEXP lower)
823
{
824
  BBOX opBBox = theOperatorBBox(operator);
825
  BBOX lowerBBox;
826
  double maxWidth = bboxWidth(opBBox);
827
 
828
  lowerBBox = operatorLimitBBox(lower);
829
  if (bboxWidth(lowerBBox) < maxWidth)
830
    return (maxWidth - bboxWidth(lowerBBox))/2;
831
  else
832
    return 0;
833
}
834
 
835
static double operatorHShift(SEXP operator, SEXP lower)
836
{
837
  BBOX opBBox = theOperatorBBox(operator);
838
  BBOX lowerBBox;
839
  double maxWidth = bboxWidth(opBBox);
840
 
841
  lowerBBox = operatorLimitBBox(lower);
842
  if (bboxWidth(lowerBBox) > maxWidth)
843
    return (bboxWidth(lowerBBox) - maxWidth)/2;
844
  else
845
    return 0;
846
}
847
 
848
static double operatorLowerHShiftAll(SEXP operator, SEXP lower, SEXP upper)
849
{
850
  BBOX opBBox = theOperatorBBox(operator);
851
  BBOX lowerBBox, upperBBox;
852
  double maxWidth = bboxWidth(opBBox);
853
 
854
  lowerBBox = operatorLimitBBox(lower);
855
  upperBBox = operatorLimitBBox(upper);
856
  maxWidth = max(maxWidth, max(bboxWidth(lowerBBox), bboxWidth(upperBBox)));
857
 
858
  if (bboxWidth(lowerBBox) < maxWidth)
859
    return (maxWidth - bboxWidth(lowerBBox))/2;
860
  else
861
    return 0;
862
}
863
 
864
static double operatorUpperHShiftAll(SEXP operator, SEXP lower, SEXP upper)
865
{
866
  BBOX opBBox = theOperatorBBox(operator);
867
  BBOX lowerBBox, upperBBox;
868
  double maxWidth = bboxWidth(opBBox);
869
 
870
  lowerBBox = operatorLimitBBox(lower);
871
  upperBBox = operatorLimitBBox(upper);
872
  maxWidth = max(maxWidth, max(bboxWidth(lowerBBox), bboxWidth(upperBBox)));
873
 
874
  if (bboxWidth(upperBBox) < maxWidth)
875
    return (maxWidth - bboxWidth(upperBBox))/2;
876
  else
877
    return 0;
878
}
879
 
880
static double operatorHShiftAll(SEXP operator, SEXP lower, SEXP upper)
881
{
882
  BBOX opBBox = theOperatorBBox(operator);
883
  BBOX lowerBBox, upperBBox;
884
  double maxWidth = bboxWidth(opBBox);
885
 
886
  lowerBBox = operatorLimitBBox(lower);
887
  upperBBox = operatorLimitBBox(upper);
888
  maxWidth = max(maxWidth, max(bboxWidth(lowerBBox), bboxWidth(upperBBox)));
889
 
890
  if (bboxWidth(opBBox) < maxWidth)
891
    return (maxWidth - bboxWidth(opBBox))/2;
892
  else
893
    return 0;
894
}
895
 
896
	/* code to generate bounding boxes and draw formulae */
897
 
898
/* Bounding box basics */
899
 
900
static BBOX makeBBox(double height, double depth, double width)
901
{
902
	BBOX bbox;
903
	bbox.height = height;
904
	bbox.depth = depth;
905
	bbox.width = width;
906
	return bbox;
907
}
908
 
909
static BBOX nullBBox()
910
{
911
	return makeBBox(0.0, 0.0, 0.0);
912
}
913
 
914
static BBOX makeBBoxFromChar(int chr)
915
{
916
	double height, depth, width;
917
	GMetricInfo(chr, &height, &depth, &width, metricUnit);
918
	return makeBBox(height, depth, width);
919
}
920
 
921
static BBOX shiftBBox(BBOX bbox, double shiftV)
922
{
923
	return makeBBox(bboxHeight(bbox) + shiftV,
924
			bboxDepth(bbox) - shiftV,
925
			bboxWidth(bbox));
926
}
927
 
928
static BBOX combineBBoxes(BBOX bbox1, BBOX bbox2)
929
{
930
	return makeBBox(max(bboxHeight(bbox1), bboxHeight(bbox2)),
931
			max(bboxDepth(bbox1), bboxDepth(bbox2)),
932
			bboxWidth(bbox1) + bboxWidth(bbox2));
933
}
934
 
935
static BBOX combineAlignedBBoxes(BBOX bbox1, BBOX bbox2)
936
{
937
	return makeBBox(max(bboxHeight(bbox1), bboxHeight(bbox2)),
938
			max(bboxDepth(bbox1), bboxDepth(bbox2)),
939
			max(bboxWidth(bbox1), bboxWidth(bbox2)));
940
}
941
 
942
/* Drawing basics */
943
 
944
static double referenceX;
945
static double referenceY;
946
static double currentX;
947
static double currentY;
948
static double currentAngle;
949
static double cosAngle;
950
static double sinAngle;
951
 
952
		/* 
953
		   // convert currentX and currentY from inches and 0 angle
954
		   // to figure units and currentAngle
955
		 */
956
static double convertedX()
957
{
958
	double rotatedX = referenceX +
959
	(currentX - referenceX) * cosAngle -
960
	(currentY - referenceY) * sinAngle;
961
	return xInchtoFig(rotatedX);
962
}
963
 
964
static double convertedY()
965
{
966
	double rotatedY = referenceY +
967
	(currentY - referenceY) * cosAngle +
968
	(currentX - referenceX) * sinAngle;
969
	return yInchtoFig(rotatedY);
970
}
971
 
972
static void moveAcross(double xamount)
973
{
974
	currentX += xamount;
975
}
976
 
977
static void moveUp(double yamount)
978
{
979
	currentY += yamount;
980
}
981
 
982
static void moveTo(double x, double y)
983
{
984
	currentX = x;
985
	currentY = y;
986
}
987
 
988
/* code for ascii atoms */
989
 
990
	/* NOTE that i assume that all symbols which have */
991
	/* been converted to ascii are in the symbol font */
992
 
993
static BBOX asciiBBox(int ascii)
994
{
995
	if ((ascii == hatAscii()) || (ascii == tildeAscii()))
996
		GP->font = 1;
997
	else
998
		GP->font = 5;
999
	return makeBBoxFromChar(ascii);
1000
}
1001
 
1002
static void drawAscii(int ascii)
1003
{
1004
	char asciiStr[2];
1005
 
1006
	if ((ascii == hatAscii()) || (ascii == tildeAscii()))
1007
		GP->font = 1;
1008
	else
1009
		GP->font = 5;
1010
	asciiStr[0] = ascii;
1011
	asciiStr[1] = '\0';
1012
	GText(convertedX(), convertedY(), asciiStr, 0.0, 0.0, currentAngle);
1013
	moveAcross(GStrWidth(asciiStr, metricUnit));
1014
}
1015
 
1016
/* code for character atoms */
1017
 
1018
static BBOX charBBox(char *str, SEXP expr)
1019
{
1020
	BBOX resultBBox = nullBBox();
1021
	int i;
1022
 
1023
	GP->font = atomFontFace(expr);
1024
	for (i = 0; i < strlen(str); i++)
1025
		resultBBox = combineBBoxes(resultBBox, makeBBoxFromChar(str[i]));
1026
 
1027
	return resultBBox;
1028
}
1029
 
1030
static void drawChar(char *str, SEXP expr)
1031
{
1032
	GP->font = atomFontFace(expr);
1033
	GText(convertedX(), convertedY(), str, 0.0, 0.0, currentAngle);
1034
	moveAcross(GStrWidth(str, metricUnit));
1035
}
1036
 
1037
/* code for symbol atoms */
1038
 
1039
static BBOX symbolBBox(SEXP expr)
1040
{
1041
	if (greekSymbol(expr))
1042
		return asciiBBox(greekAscii(expr));
1043
	else
1044
		return charBBox(CHAR(PRINTNAME(expr)), expr);
1045
}
1046
 
1047
static void drawSymbol(SEXP expr)
1048
{
1049
	if (greekSymbol(expr))
1050
		drawAscii(greekAscii(expr));
1051
	else
1052
		drawChar(CHAR(PRINTNAME(expr)), expr);
1053
}
1054
 
1055
/* code for numeric atoms */
1056
 
1057
static BBOX numberBBox(SEXP expr)
1058
{
1059
	return charBBox(CHAR(asChar(expr)), expr);
1060
}
1061
 
1062
static void drawNumber(SEXP expr)
1063
{
1064
	drawChar(CHAR(asChar(expr)), expr);
1065
}
1066
 
1067
/* code for string atoms */
1068
 
1069
static BBOX stringBBox(SEXP expr)
1070
{
1071
	return charBBox(CHAR(STRING(expr)[0]), expr);
1072
}
1073
 
1074
static void drawString(SEXP expr)
1075
{
1076
	drawChar(CHAR(STRING(expr)[0]), expr);
1077
}
1078
 
1079
/* code for atoms */
1080
 
1081
static BBOX atomBBox(SEXP expr)
1082
{
1083
	if (symbolAtom(expr))
1084
		return symbolBBox(expr);
1085
	else if (numberAtom(expr))
1086
		return numberBBox(expr);
1087
	else if (stringAtom(expr))
1088
		return stringBBox(expr);
1089
}
1090
 
1091
static void drawAtom(SEXP expr)
1092
{
1093
	if (symbolAtom(expr))
1094
		drawSymbol(expr);
1095
	else if (numberAtom(expr))
1096
		drawNumber(expr);
1097
	else if (stringAtom(expr))
1098
		drawString(expr);
1099
}
1100
 
1101
/* code for italic corrections */
1102
 
1103
static double half_pi = 1.57079632679489661922;
1104
 
1105
static double italicCorrection(SEXP expr)
1106
{
1107
  BBOX exprBBox = elementBBox(expr);
1108
  return bboxHeight(exprBBox) * tan(half_pi / 6);
1109
}
1110
 
1111
	/* correction within expression checks for current font italic */
1112
 
1113
static BBOX correctionWithinBBox(SEXP expr)
1114
{
1115
  if (isItalic() && !nonItalicExpression(expr))
1116
    return makeBBox(0, 0, italicCorrection(expr));
1117
  else
1118
    return nullBBox();
1119
}
1120
 
1121
static void drawCorrectionWithin(SEXP expr)
1122
{
1123
  if (isItalic() && !nonItalicExpression(expr))
1124
    moveAcross(italicCorrection(expr));
1125
}    
1126
 
1127
	/* correction between expressions checks current font and font */
1128
	/* of each expression */
1129
 
1130
static BBOX correctionBetweenBBox(SEXP expr1, SEXP expr2)
1131
{
1132
  if (((isItalic() && !nonItalicExpression(expr1)) ||
1133
       italicExpression(expr1)) &&
1134
      ((!isItalic() && !italicExpression(expr2)) ||
1135
       nonItalicExpression(expr2)))
1136
    return makeBBox(0, 0, italicCorrection(expr1));
1137
  else
1138
    return nullBBox();
1139
}
1140
 
1141
static void drawCorrectionBetween(SEXP expr1, SEXP expr2)
1142
{
1143
  if (((isItalic() && !nonItalicExpression(expr1)) ||
1144
       italicExpression(expr1)) &&
1145
      ((!isItalic() && !italicExpression(expr2)) ||
1146
       nonItalicExpression(expr2)))
1147
    moveAcross(italicCorrection(expr1));
1148
}
1149
 
1150
/* code for gaps */
1151
 
1152
static int cexGap = 1;
1153
 
1154
static void setGapCEX()
1155
{
1156
  cexGap = GP->cex;
1157
}
1158
 
1159
static BBOX gapBBox(double gap)
1160
{
1161
  double cexSaved = GP->cex;
1162
  BBOX theBBox;
1163
 
1164
  GP->cex = cexGap;
1165
  theBBox = makeBBox(0, 0, gap * fontHeight());
1166
  GP->cex = cexSaved;
1167
 
1168
  return theBBox;
1169
}
1170
 
1171
static BBOX smallgapBBox(double gap)
1172
{
1173
  double cexSaved = GP->cex;
1174
  BBOX theBBox;
1175
 
1176
  GP->cex = cexGap;
1177
  theBBox = makeBBox(0, 0, 0.5 * gap * fontHeight());
1178
  GP->cex = cexSaved;
1179
 
1180
  return theBBox;
1181
}
1182
 
1183
static void drawGap(double gap)
1184
{
1185
  double cexSaved = GP->cex;
1186
 
1187
  GP->cex = cexGap;
1188
  moveAcross(gap * fontHeight());
1189
  GP->cex = cexSaved;
1190
}
1191
 
1192
static void drawSmallGap(double gap)
1193
{
1194
  double cexSaved = GP->cex;
1195
 
1196
  GP->cex = cexGap;
1197
  moveAcross(0.5 * gap * fontHeight());
1198
  GP->cex = cexSaved;
1199
}
1200
 
1201
/* code for binary operator (+, -, *, /) expressions */
1202
 
1203
/* NOTE that gaps are specified as proportions of the current font height */
1204
 
1205
static double binGapBefore(SEXP beforeOperand)
1206
{
1207
  return 0.2;
1208
}
1209
 
1210
static double binGapBetween(SEXP operand1, SEXP operand2)
1211
{
1212
    return 0;
1213
}
1214
 
1215
static double binGapAfter(SEXP afterOperand)
1216
{
1217
    return 0.2;
1218
}
1219
 
1220
static BBOX binBBox(SEXP expr)
1221
{
1222
	SEXP operator, operand1, operand2;
1223
	BBOX middleBBox;
1224
 
1225
	operator = CAR(expr);
1226
	operand1 = CADR(expr);
1227
        setGapCEX();
1228
	if(length(expr) == 3) {
1229
		operand2 = CADDR(expr);
1230
		if (multiplicationOperator(operator))
1231
			middleBBox = 
1232
			  correctionBetweenBBox(operand1, operand2);
1233
		else 
1234
			middleBBox = 
1235
                          combineBBoxes(
1236
                            gapBBox(binGapBefore(operand1)),
1237
			    combineBBoxes(atomBBox(operator),
1238
					  gapBBox(binGapAfter(operand2))));
1239
 
1240
		return combineBBoxes(elementBBox(operand1),
1241
				     combineBBoxes(middleBBox,
1242
						   elementBBox(operand2)));
1243
	}
1244
	else if(length(expr) == 2) {
1245
		middleBBox = combineBBoxes(atomBBox(operator),
1246
				   smallgapBBox(binGapAfter(operand1)));
1247
		return combineBBoxes(middleBBox, elementBBox(operand1));
1248
	}
1249
	else error("invalid formula\n");
1250
}
1251
 
1252
static void drawBin(SEXP expr)
1253
{
1254
	SEXP operator, operand1, operand2;
1255
 
1256
	operator = CAR(expr);
1257
	operand1 = CADR(expr);
1258
	setGapCEX();
1259
	if(length(expr) == 3) {
1260
		operand2 = CADDR(expr);
1261
		drawElement(operand1);
1262
		if (multiplicationOperator(operator)) 
1263
		  drawGap(binGapBetween(operand1, operand2));
1264
		else {
1265
			drawGap(binGapBefore(operand1));
1266
			drawAtom(operator);
1267
			drawGap(binGapAfter(operand2));
1268
		}
1269
		drawElement(operand2);
1270
	}
1271
	else {
1272
		drawAtom(operator);
1273
		drawSmallGap(binGapAfter(operand1));
1274
		drawElement(operand1);
1275
	}
1276
}
1277
 
1278
/* code for superscript and subscript expressions */
1279
 
1280
static BBOX supsubBBox(SEXP body, SEXP superscript, SEXP subscript);
1281
 
1282
static BBOX superscriptBBox(SEXP superscript)
1283
{
1284
	BBOX result;
1285
	float cexSaved = GP->cex;
1286
 
1287
	GP->cex = GP->cex * scriptScale;
1288
	result = elementBBox(superscript);
1289
	GP->cex = cexSaved;
1290
 
1291
	return result;
1292
}
1293
 
1294
static BBOX supBBox(SEXP expr)
1295
{
1296
	SEXP body = CADR(expr);
1297
	SEXP superscript = CADDR(expr);
1298
	int supsub = 0;
1299
 
1300
	if (formulaExpression(body))
1301
		if (subAtom(CAR(body)))
1302
			supsub = 1;
1303
 
1304
	if (supsub)
1305
		return supsubBBox(CADR(body), superscript, (CADDR(body)));
1306
	else
1307
		return combineBBoxes(
1308
			 elementBBox(body),
1309
			 combineBBoxes(
1310
			   correctionWithinBBox(body),
1311
			   shiftBBox(superscriptBBox(superscript),
1312
				     superscriptShift(body, superscript))));
1313
}
1314
 
1315
static BBOX subscriptBBox(SEXP subscript)
1316
{
1317
	BBOX result;
1318
	float cexSaved = GP->cex;
1319
 
1320
	GP->cex = GP->cex * scriptScale;
1321
	result = elementBBox(subscript);
1322
	GP->cex = cexSaved;
1323
 
1324
	return result;
1325
}
1326
 
1327
static BBOX subBBox(SEXP expr)
1328
{
1329
	SEXP body = CADR(expr);
1330
	SEXP subscript = CADDR(expr);
1331
 
1332
	return combineBBoxes(elementBBox(body),
1333
		             shiftBBox(subscriptBBox(subscript),
1334
			               subscriptShift(body, subscript, 1)));
1335
}
1336
 
1337
static BBOX supsubBBox(SEXP body, SEXP superscript, SEXP subscript)
1338
{
1339
	double supShift, subShift;
1340
	supsubShift(body, superscript, subscript, &supShift, &subShift);
1341
 
1342
	return combineBBoxes(
1343
		 elementBBox(body),
1344
		 combineAlignedBBoxes(
1345
		   combineBBoxes(
1346
		     correctionWithinBBox(body),
1347
		     shiftBBox(superscriptBBox(superscript), supShift)),
1348
		   shiftBBox(subscriptBBox(subscript), subShift)));
1349
}
1350
 
1351
static void drawScriptElement(SEXP expr)
1352
{
1353
	float cexSaved = GP->cex;
1354
 
1355
	GP->cex = GP->cex * scriptScale;
1356
	drawElement(expr);
1357
	GP->cex = cexSaved;
1358
}
1359
 
1360
static void drawSupSub(SEXP body, SEXP superscript, SEXP subscript);
1361
 
1362
static void drawSuper(SEXP expr)
1363
{
1364
	SEXP body = CADR(expr);
1365
	SEXP superscript = CADDR(expr);
1366
	double supShift = superscriptShift(body, superscript);
1367
	int supsub = 0;
1368
 
1369
	if (formulaExpression(body))
1370
		if (subAtom(CAR(body)))
1371
			supsub = 1;
1372
 
1373
	if (supsub)
1374
		drawSupSub(CADR(body), superscript, CADDR(body));
1375
	else {
1376
		drawElement(body);
1377
		drawCorrectionWithin(body);
1378
		moveUp(supShift);
1379
		drawScriptElement(superscript);
1380
		moveUp(-supShift);
1381
	}
1382
}
1383
 
1384
static void drawSub(SEXP expr)
1385
{
1386
	SEXP body = CADR(expr);
1387
	SEXP subscript = CADDR(expr);
1388
	double subShift = subscriptShift(body, subscript, 1);
1389
 
1390
	drawElement(body);
1391
	moveUp(-subShift);
1392
	drawScriptElement(subscript);
1393
	moveUp(subShift);
1394
}
1395
 
1396
static void drawSupSub(SEXP body, SEXP superscript, SEXP subscript)
1397
{
1398
	double supShift, subShift;
1399
	double savedX, savedY;
1400
	BBOX supBBox = elementBBox(superscript);
1401
	BBOX subBBox = elementBBox(subscript);
1402
 
1403
	supsubShift(body, superscript, subscript, &supShift, &subShift);
1404
	drawElement(body);
1405
	savedX = currentX;
1406
	savedY = currentY;
1407
	drawCorrectionWithin(body);
1408
	moveUp(supShift);
1409
	drawScriptElement(superscript);
1410
	moveTo(savedX, savedY);
1411
	moveUp(-subShift);
1412
	drawScriptElement(subscript);
1413
	moveTo(savedX, savedY);
1414
	moveAcross(max(bboxWidth(supBBox), bboxWidth(subBBox)));
1415
}
1416
 
1417
/* code for accented expressions (hat, bar, ...) */
1418
 
1419
static BBOX hatBBox(SEXP body)
1420
{
1421
	BBOX bodyBBox = elementBBox(body);
1422
	return combineAlignedBBoxes(bodyBBox,
1423
				    makeBBox(bboxHeight(bodyBBox) +
1424
					     customAccentGap() +
1425
					     customHatHeight(), 0, 0));
1426
}
1427
 
1428
static BBOX barBBox(SEXP body)
1429
{
1430
	BBOX bodyBBox = elementBBox(body);
1431
	return combineAlignedBBoxes(bodyBBox,
1432
				    makeBBox(bboxHeight(bodyBBox) +
1433
					     customAccentGap(), 0, 0));
1434
}
1435
 
1436
static BBOX accentBBox(SEXP expr)
1437
{
1438
	SEXP accent = CAR(expr);
1439
	SEXP body = CADR(expr);
1440
 
1441
	if (hatAtom(accent))
1442
		return hatBBox(body);
1443
	else if (barAtom(accent))
1444
		return barBBox(body);
1445
	else
1446
		return combineAlignedBBoxes(
1447
						   elementBBox(body),
1448
		combineBBoxes(makeBBox(accentHShift(body, accent), 0, 0),
1449
			      shiftBBox(asciiBBox(accentAscii(accent)),
1450
					accentVShift(body))));
1451
}
1452
 
1453
static void drawHat(SEXP body)
1454
{
1455
	BBOX bodyBBox = elementBBox(body);
1456
	double width = bboxWidth(bodyBBox);
1457
	double savedX = currentX;
1458
	double savedY = currentY;
1459
 
1460
	moveUp(bboxHeight(bodyBBox) + customAccentGap());
1461
	GStartPath();
1462
	GMoveTo(convertedX(), convertedY());
1463
	moveUp(customHatHeight());
1464
	moveAcross(width / 2);
1465
	GLineTo(convertedX(), convertedY());
1466
	moveUp(-customHatHeight());
1467
	moveAcross(width / 2);
1468
	GLineTo(convertedX(), convertedY());
1469
	GEndPath();
1470
	moveTo(savedX, savedY);
1471
	drawElement(body);
1472
}
1473
 
1474
static void drawBar(SEXP body)
1475
{
1476
	BBOX bodyBBox = elementBBox(body);
1477
	double savedX = currentX;
1478
	double savedY = currentY;
1479
 
1480
	moveUp(bboxHeight(bodyBBox) + customAccentGap());
1481
	GStartPath();
1482
	GMoveTo(convertedX(), convertedY());
1483
	moveAcross(bboxWidth(bodyBBox));
1484
	GLineTo(convertedX(), convertedY());
1485
	GEndPath();
1486
	moveTo(savedX, savedY);
1487
	drawElement(body);
1488
}
1489
 
1490
static void drawAccent(SEXP expr)
1491
{
1492
	SEXP accent = CAR(expr);
1493
	SEXP body = CADR(expr);
1494
	double savedX = currentX;
1495
	double savedY = currentY;
1496
 
1497
	if (hatAtom(accent))
1498
		drawHat(body);
1499
	else if (barAtom(accent))
1500
		drawBar(body);
1501
	else {
1502
		moveAcross(accentHShift(body, accent));
1503
		moveUp(accentVShift(body));
1504
		drawAscii(accentAscii(accent));
1505
		moveTo(savedX, savedY);
1506
		drawElement(body);
1507
	}
1508
}
1509
 
1510
/* code for fraction expressions (over) */
1511
 
1512
static BBOX fractionBBox(SEXP expr)
1513
{
1514
	SEXP numerator = CADR(expr);
1515
	SEXP denominator = CADDR(expr);
1516
	BBOX numBBox, denomBBox;
1517
	double numHShift, denomHShift;
1518
	float cexSaved = GP->cex;
1519
 
1520
#ifdef OLD
1521
	GP->cex = GP->cex * scriptScale;
1522
#else
1523
	GP->cex = GP->cex * ratioScale;
1524
#endif
1525
	numBBox = elementBBox(numerator);
1526
	denomBBox = elementBBox(denominator);
1527
#ifdef OLD
1528
	GP->cex = cexSaved;
1529
#else
1530
	GP->cex = cexSaved;
1531
#endif
1532
	numdenomHShift(numerator, denominator, &numHShift, &denomHShift);
1533
 
1534
	return combineAlignedBBoxes(
1535
	     shiftBBox(combineBBoxes(makeBBox(numHShift, 0, 0), numBBox),
1536
		       numeratorVShift(numerator)),
1537
	 shiftBBox(combineBBoxes(makeBBox(denomHShift, 0, 0), denomBBox),
1538
		   -denominatorVShift(denominator)));
1539
}
1540
 
1541
static void drawRatioElement(SEXP expr)
1542
{
1543
	float cexSaved = GP->cex;
1544
	GP->cex = GP->cex * ratioScale;
1545
	drawElement(expr);
1546
	GP->cex = cexSaved;
1547
}
1548
 
1549
static void drawFraction(SEXP expr)
1550
{
1551
	SEXP numerator = CADR(expr);
1552
	SEXP denominator = CADDR(expr);
1553
	double savedX = currentX;
1554
	double savedY = currentY;
1555
	double fWidth = fractionWidth(numerator, denominator);
1556
	double numHShift, denomHShift;
1557
 
1558
	numdenomHShift(numerator, denominator, &numHShift, &denomHShift);
1559
	moveAcross(numHShift);
1560
	moveUp(numeratorVShift(numerator));
1561
#ifdef OLD
1562
	drawScriptElement(numerator);
1563
#else
1564
	drawRatioElement(numerator);
1565
#endif
1566
	moveTo(savedX, savedY);
1567
	moveUp(axisHeight());
1568
	GStartPath();
1569
	GMoveTo(convertedX(), convertedY());
1570
	moveAcross(fWidth);
1571
	GLineTo(convertedX(), convertedY());
1572
	GEndPath();
1573
	moveTo(savedX, savedY);
1574
	moveAcross(denomHShift);
1575
	moveUp(-denominatorVShift(denominator));
1576
#ifdef OLD
1577
	drawScriptElement(denominator);
1578
#else
1579
	drawRatioElement(denominator);
1580
#endif
1581
	moveTo(savedX + fWidth, savedY);
1582
}
1583
 
1584
/* code for group expressions (expressions within parentheses) */
1585
 
1586
static BBOX groupBBox(SEXP expr)
1587
{
1588
	return combineBBoxes(
1589
		 asciiBBox(groupOpenAscii()),
1590
		 combineBBoxes(
1591
		   elementBBox(CADR(expr)),
1592
		   combineBBoxes(correctionWithinBBox(CADR(expr)),
1593
				 asciiBBox(groupCloseAscii()))));
1594
}
1595
 
1596
static void drawGroup(SEXP expr)
1597
{
1598
	drawAscii(groupOpenAscii());
1599
	drawElement(CADR(expr));
1600
	drawCorrectionWithin(CADR(expr));
1601
	drawAscii(groupCloseAscii());
1602
}
1603
 
1604
/* code for operator expressions (sum, product, integral) */
1605
 
1606
/* NOTE that gaps are specified as proportions of the current font height */
1607
 
1608
static double operatorGap(SEXP body)
1609
{
1610
    return 0.1;
1611
}
1612
 
1613
static double integralTopShift() { return 0.5 * fontHeight(); }
1614
 
1615
static double integralBottomShift() { return -0.5 * fontHeight(); }
1616
 
1617
static BBOX theOperatorBBox(SEXP operator)
1618
{
1619
  if (integralOperator(operator))
1620
    return combineAlignedBBoxes(
1621
	     shiftBBox(asciiBBox(integralAscii(1)), integralTopShift()),
1622
	     combineAlignedBBoxes(asciiBBox(integralAscii(2)),
1623
				  shiftBBox(asciiBBox(integralAscii(3)),
1624
					    integralBottomShift())));	
1625
  else
1626
    return asciiBBox(operatorAscii(operator));
1627
}
1628
 
1629
static useRelGap = 1;
1630
 
1631
static BBOX operatorLimitBBox(SEXP limit)
1632
{
1633
  float cexSaved = GP->cex;
1634
  BBOX limitBBox;
1635
 
1636
  GP->cex = GP->cex * scriptScale;
1637
  useRelGap = 0;
1638
  limitBBox = elementBBox(limit);
1639
  useRelGap = 1;
1640
  GP->cex = cexSaved;
1641
 
1642
  return limitBBox;
1643
}
1644
 
1645
static BBOX operatorBBox(SEXP expr)
1646
{
1647
  SEXP operator = CAR(expr);
1648
  SEXP body, lower, upper;
1649
  BBOX opBBox = theOperatorBBox(operator);
1650
  BBOX bodyBBox, lowerBBox, upperBBox;
1651
  setGapCEX();
1652
 
1653
  if (length(expr) > 1) {
1654
    body = CADR(expr);
1655
    bodyBBox = combineBBoxes(opBBox,
1656
                             combineBBoxes(gapBBox(operatorGap(body)), 
1657
					   elementBBox(body)));
1658
 
1659
    if (length(expr) > 2) {
1660
      lower = CADDR(expr);
1661
      lowerBBox = operatorLimitBBox(lower);
1662
 
1663
      if (length(expr) > 3) {
1664
	upper = CADDDR(expr);
1665
	upperBBox = operatorLimitBBox(upper);
1666
 
1667
	return combineAlignedBBoxes(
1668
		 combineBBoxes(
1669
                   makeBBox(operatorHShiftAll(operator, lower, upper), 0, 0),
1670
		   bodyBBox),
1671
		 combineAlignedBBoxes(
1672
                   shiftBBox(
1673
                     combineBBoxes(
1674
                       makeBBox(operatorUpperHShiftAll(operator, lower, upper),
1675
				0, 0),
1676
		       upperBBox),
1677
		     operatorUpperShift(operator, upper)),
1678
		   shiftBBox(
1679
		     combineBBoxes(
1680
		       makeBBox(operatorLowerHShiftAll(operator, lower, upper),
1681
				0, 0),
1682
		       lowerBBox),
1683
		     operatorLowerShift(operator, lower))));
1684
      }
1685
      else
1686
	return combineAlignedBBoxes(
1687
                 combineBBoxes(
1688
		   makeBBox(operatorHShift(operator, lower), 0, 0),
1689
		   bodyBBox),
1690
		 shiftBBox(
1691
		   combineBBoxes(
1692
		     makeBBox(operatorLowerHShift(operator, lower), 0, 0),
1693
		     lowerBBox),
1694
		   operatorLowerShift(operator, lower)));
1695
    }
1696
    else
1697
      return bodyBBox;
1698
  }
1699
  else 
1700
    error("Invalid Formula\n");
1701
 
1702
}
1703
 
1704
static void drawTheOperator(SEXP operator)
1705
{
1706
  if (integralOperator(operator)) {
1707
    double savedX = currentX;
1708
    double savedY = currentY;
1709
    moveUp(integralTopShift());
1710
    drawAscii(integralAscii(1));
1711
    moveTo(savedX, savedY);
1712
    moveUp(integralBottomShift());
1713
    drawAscii(integralAscii(3));
1714
    moveTo(savedX, savedY);
1715
    drawAscii(integralAscii(2));
1716
  }
1717
  else
1718
    drawAscii(operatorAscii(operator));
1719
}
1720
 
1721
static void drawOperatorLimit(SEXP limit)
1722
{
1723
  useRelGap = 0;
1724
  drawScriptElement(limit);
1725
  useRelGap = 1;
1726
}
1727
 
1728
static void drawOperator(SEXP expr)
1729
{
1730
  SEXP operator = CAR(expr);
1731
  SEXP body = CADR(expr);
1732
  SEXP lower, upper;
1733
  double savedX = currentX;
1734
  double savedY = currentY;
1735
 
1736
  setGapCEX();
1737
 
1738
  if (length(expr) > 2) {
1739
    lower = CADDR(expr);
1740
 
1741
    if (length(expr) > 3) {
1742
      upper = CADDDR(expr);
1743
      moveUp(operatorUpperShift(operator, upper));
1744
      moveAcross(operatorUpperHShiftAll(operator, lower, upper));
1745
      drawOperatorLimit(upper);
1746
      moveTo(savedX, savedY);
1747
      moveUp(-operatorLowerShift(operator, lower));
1748
      moveAcross(operatorLowerHShiftAll(operator, lower, upper));
1749
      drawOperatorLimit(lower);
1750
      moveTo(savedX, savedY);
1751
      moveAcross(operatorHShiftAll(operator, lower, upper));
1752
    }
1753
 
1754
    else{
1755
      moveUp(-operatorLowerShift(operator, lower));
1756
      moveAcross(operatorLowerHShift(operator, lower));
1757
      drawOperatorLimit(lower);
1758
      moveTo(savedX, savedY);
1759
      moveAcross(operatorHShift(operator, lower));
1760
    }
1761
  }
1762
 
1763
  drawTheOperator(operator);
1764
  drawGap(operatorGap(body));
1765
  drawElement(body);
1766
}
1767
 
1768
/* code for radical expressions (root) */
1769
 
1770
static BBOX customRadicalBBox(SEXP body)
1771
{
1772
	BBOX bodyBBox = elementBBox(body);
1773
	return combineBBoxes(makeBBox(bboxHeight(bodyBBox) + customRadicalGap(),
1774
				      0, customRadicalWidth()),
1775
		      combineBBoxes(makeBBox(0, 0, customRadicalSpace()),
1776
				    bodyBBox));
1777
}
1778
 
1779
static BBOX radicalBBox(SEXP expr)
1780
{
1781
	SEXP body = CADR(expr);
1782
	return customRadicalBBox(body);
1783
}
1784
 
1785
static void drawCustomRadical(SEXP body)
1786
{
1787
	BBOX bodyBBox = elementBBox(body);
1788
	double height = bboxHeight(bodyBBox);
1789
	double depth = bboxDepth(bodyBBox);
1790
	double width = bboxWidth(bodyBBox);
1791
	double twiddleHeight = (height - depth) / 2;
1792
	double savedX = currentX;
1793
	double savedY = currentY;
1794
 
1795
	moveUp(0.8 * twiddleHeight);
1796
	GStartPath();
1797
	GMoveTo(convertedX(), convertedY());
1798
	moveUp(0.2 * twiddleHeight);
1799
	moveAcross(0.3 * customRadicalWidth());
1800
	GLineTo(convertedX(), convertedY());
1801
	moveUp(-(twiddleHeight + depth));
1802
	moveAcross(0.3 * customRadicalWidth());
1803
	GLineTo(convertedX(), convertedY());
1804
	moveUp(depth + height + customRadicalGap());
1805
	moveAcross(0.4 * customRadicalWidth());
1806
	GLineTo(convertedX(), convertedY());
1807
	moveAcross(customRadicalSpace() + width);
1808
	GLineTo(convertedX(), convertedY());
1809
	GEndPath();
1810
	moveTo(savedX, savedY);
1811
	moveAcross(customRadicalWidth() + customRadicalSpace());
1812
	drawElement(body);
1813
}
1814
 
1815
static void drawRadical(SEXP expr)
1816
{
1817
	SEXP body = CADR(expr);
1818
	drawCustomRadical(body);
1819
}
1820
 
1821
/* code for absolute expressions (abs) */
1822
 
1823
static BBOX absBBox(SEXP expr)
1824
{
1825
	SEXP body = CADR(expr);
1826
	return combineBBoxes(makeBBox(0, 0, absSpace()),
1827
			     combineBBoxes(elementBBox(body),
1828
					   makeBBox(0, 0, absSpace())));
1829
}
1830
 
1831
static void drawAbs(SEXP expr)
1832
{
1833
	SEXP body = CADR(expr);
1834
	BBOX bodyBBox = elementBBox(expr);
1835
	double height = bboxHeight(bodyBBox);
1836
	double depth = bboxDepth(bodyBBox);
1837
 
1838
	moveUp(-depth);
1839
	GStartPath();
1840
	GMoveTo(convertedX(), convertedY());
1841
	moveUp(depth + height);
1842
	GLineTo(convertedX(), convertedY());
1843
	moveUp(-height);
1844
	moveAcross(absSpace());
1845
	drawElement(body);
1846
	moveAcross(absSpace());
1847
	moveUp(-depth);
1848
	GMoveTo(convertedX(), convertedY());
1849
	moveUp(depth + height);
1850
	GLineTo(convertedX(), convertedY());
1851
	GEndPath();
1852
	moveUp(-height);
1853
}
1854
 
1855
/* code for general expressions with no special meaning in */
1856
/* mathematical notation syntax (e.g., f(x)) */
1857
 
1858
static BBOX expressionBBox(SEXP expr)
1859
{
1860
	int i;
1861
	int numParams = length(expr) - 1;
1862
	BBOX resultBBox = elementBBox(CAR(expr));
1863
        SEXP lastTerm;
1864
 
1865
	lastTerm = CAR(expr);
1866
	expr = CDR(expr);
1867
	resultBBox = combineBBoxes(resultBBox, asciiBBox(groupOpenAscii()));
1868
	for (i = 0; i < numParams; i++) {
1869
		resultBBox = combineBBoxes(resultBBox, elementBBox(CAR(expr)));
1870
	        lastTerm = CAR(expr);
1871
		expr = CDR(expr);
1872
		if (i < numParams - 1)
1873
			resultBBox = combineBBoxes(resultBBox,
1874
				   combineBBoxes(asciiBBox(commaAscii()),
1875
					       asciiBBox(spaceAscii())));
1876
	}
1877
	return combineBBoxes(resultBBox, 
1878
			     combineBBoxes(correctionWithinBBox(lastTerm),
1879
					   asciiBBox(groupCloseAscii())));
1880
}
1881
 
1882
static void drawExpression(SEXP expr)
1883
{
1884
	int i;
1885
	int numParams = length(expr) - 1;
1886
	SEXP lastTerm;
1887
 
1888
	drawElement(CAR(expr));
1889
	lastTerm = CAR(expr);
1890
	expr = CDR(expr);
1891
	drawAscii(groupOpenAscii());
1892
	for (i = 0; i < numParams; i++) {
1893
		drawElement(CAR(expr));
1894
	        lastTerm = CAR(expr);
1895
		expr = CDR(expr);
1896
		if (i < numParams - 1) {
1897
			drawAscii(commaAscii());
1898
			drawAscii(spaceAscii());
1899
		}
1900
	}
1901
	drawCorrectionWithin(lastTerm);
1902
	drawAscii(groupCloseAscii());
1903
}
1904
 
1905
/* code for curly expressions (i.e., { ... } ) */
1906
 
1907
static BBOX curlyBBox(SEXP expr)
1908
{
1909
	return expressionBBox(CADR(expr));
1910
}
1911
 
1912
static void drawFormula(SEXP);
1913
 
526 maechler 1914
static void drawCurly(SEXP expr)
2 r 1915
{
1916
	drawFormula(CADR(expr));
1917
}
1918
 
1919
/* code for relation expressions (i.e. ... == ...) */
1920
 
1921
static double relGap()
1922
{
1923
  if (useRelGap)
1924
    return 0.3;
1925
  else
1926
    return 0.1;
1927
}
1928
 
1929
static BBOX relBBox(SEXP expr)
1930
{
1931
  SEXP arg1 = CADR(expr);
1932
  SEXP arg2 = CADDR(expr);
1933
 
1934
  return combineBBoxes(
1935
	   elementBBox(arg1),
1936
	   combineBBoxes(
1937
			 gapBBox(relGap()),
1938
			 combineBBoxes(
1939
				       asciiBBox(relAscii()),
1940
				       combineBBoxes(
1941
						     gapBBox(relGap()),
1942
						     elementBBox(arg2)))));
1943
}
1944
 
1945
static void drawRel(SEXP expr)
1946
{
1947
  SEXP arg1 = CADR(expr);
1948
  SEXP arg2 = CADDR(expr);
1949
 
1950
  drawElement(arg1);
1951
  drawGap(relGap());
1952
  drawAscii(relAscii());
1953
  drawGap(relGap());
1954
  drawElement(arg2);
1955
}
1956
 
1957
/* code for bold expressions */
1958
 
1959
static BBOX boldBBox(SEXP expr)
1960
{
1961
  BBOX result;
1962
  int savedFont = getFont();
1963
 
1964
  boldFont();
1965
  result = elementBBox(CADR(expr));
1966
  setFont(savedFont);
1967
 
1968
  return result;
1969
}
1970
 
1971
static void drawBold(SEXP expr)
1972
{
1973
  int savedFont = getFont();
1974
 
1975
  boldFont();
1976
  drawElement(CADR(expr));
1977
  setFont(savedFont);
1978
}
1979
 
1980
/* code for italic expressions */
1981
 
1982
static BBOX italicBBox(SEXP expr)
1983
{
1984
  BBOX result;
1985
  SEXP body = CADR(expr);
1986
  int savedFont = getFont();
1987
 
1988
  italicFont();
1989
  result = elementBBox(body);
1990
  setFont(savedFont);
1991
 
1992
  return result;
1993
}
1994
 
1995
static void drawItalic(SEXP expr)
1996
{
1997
  SEXP body = CADR(expr);
1998
  int savedFont = getFont();
1999
 
2000
  italicFont();
2001
  drawElement(body);
2002
  setFont(savedFont);
2003
}
2004
 
2005
/* code for plain expressions */
2006
 
2007
static BBOX plainBBox(SEXP expr)
2008
{
2009
  BBOX result = nullBBox();
2010
  int savedFont = getFont();
2011
 
2012
  plainFont();
2013
  result = elementBBox(CADR(expr));
2014
  setFont(savedFont);
2015
 
2016
  return result;
2017
}
2018
 
2019
static void drawPlain(SEXP expr)
2020
{
2021
  int savedFont = getFont();
2022
 
2023
  plainFont();
2024
  drawElement(CADR(expr));
2025
  setFont(savedFont);
2026
}
2027
 
2028
/* code for bolditalic expressions */
2029
 
2030
static BBOX boldItalicBBox(SEXP expr)
2031
{
2032
  BBOX result;
2033
  int savedFont = getFont();
2034
 
2035
  boldItalicFont();
2036
  result = elementBBox(CADR(expr));
2037
  setFont(savedFont);
2038
 
2039
  return result;
2040
}
2041
 
2042
static void drawBoldItalic(SEXP expr)
2043
{
2044
  int savedFont = getFont();
2045
 
2046
  boldItalicFont();
2047
  drawElement(CADR(expr));
2048
  setFont(savedFont);
2049
}
2050
 
2051
/* code for concatenating expressions c(...) */
2052
 
2053
static BBOX concatenateBBox(SEXP expr)
2054
{
2055
  SEXP args = CDR(expr);
2056
  SEXP lastArg;
2057
  int i;
2058
  int numArgs = length(args);
2059
  BBOX result = nullBBox();
2060
 
2061
  if (numArgs > 0)
2062
  result = elementBBox(CAR(args));
2063
  lastArg = CAR(args);
2064
  args = CDR(args);
2065
 
2066
  for (i=1; i<numArgs; i++) {
2067
    result = combineBBoxes(
2068
	       result, 
2069
	       combineBBoxes(correctionBetweenBBox(lastArg, CAR(args)),
2070
			     elementBBox(CAR(args))));
2071
    lastArg = CAR(args);
2072
    args = CDR(args);
2073
  }
2074
 
2075
  return result;
2076
}
2077
 
2078
static void drawConcatenate(SEXP expr)
2079
{
2080
  SEXP args = CDR(expr);
2081
  SEXP lastArg;
2082
  int i;
2083
  int numArgs = length(args);
2084
 
2085
  for (i=0; i<numArgs; i++) {
2086
    if (i > 0)
2087
      drawCorrectionBetween(lastArg, CAR(args));
2088
    drawElement(CAR(args));
2089
    lastArg = CAR(args);
2090
    args = CDR(args);
2091
  }
2092
}
2093
 
2094
/* dispatching procedure which determines nature of expression */
2095
 
2096
static BBOX formulaBBox(SEXP expr)
2097
{
2098
	SEXP head = CAR(expr);
2099
 
2100
	if (binAtom(head))
2101
		return binBBox(expr);
2102
	else if (superAtom(head))
2103
		return supBBox(expr);
2104
	else if (subAtom(head))
2105
		return subBBox(expr);
2106
	else if (accentAtom(head))
2107
		return accentBBox(expr);
2108
	else if (fractionAtom(head))
2109
		return fractionBBox(expr);
2110
	else if (groupAtom(head))
2111
		return groupBBox(expr);
2112
	else if (operatorAtom(head))
2113
		return operatorBBox(expr);
2114
	else if (radicalAtom(head))
2115
		return radicalBBox(expr);
2116
	else if (absAtom(head))
2117
		return absBBox(expr);
2118
	else if (curlyAtom(head))
2119
		return curlyBBox(expr);
2120
	else if (relAtom(head))
2121
	  return relBBox(expr);
2122
	else if (boldAtom(head))
2123
	  return boldBBox(expr);
2124
	else if (italicAtom(head))
2125
	  return italicBBox(expr);
2126
	else if (plainAtom(head))
2127
	  return plainBBox(expr);
2128
	else if (boldItalicAtom(head))
2129
	  return boldItalicBBox(expr);
2130
	else if (concatenateAtom(head))
2131
		return concatenateBBox(expr);
2132
	else
2133
		return expressionBBox(expr);
2134
}
2135
 
2136
static void drawFormula(SEXP expr)
2137
{
2138
	SEXP head = CAR(expr);
2139
 
2140
	if (binAtom(head))
2141
		drawBin(expr);
2142
	else if (superAtom(head))
2143
		drawSuper(expr);
2144
	else if (subAtom(head))
2145
		drawSub(expr);
2146
	else if (accentAtom(head))
2147
		drawAccent(expr);
2148
	else if (fractionAtom(head))
2149
		drawFraction(expr);
2150
	else if (groupAtom(head))
2151
		drawGroup(expr);
2152
	else if (operatorAtom(head))
2153
		drawOperator(expr);
2154
	else if (radicalAtom(head))
2155
		drawRadical(expr);
2156
	else if (absAtom(head))
2157
		drawAbs(expr);
2158
	else if (curlyAtom(head))
2159
		drawCurly(expr);
2160
	else if (relAtom(head))
2161
	  drawRel(expr);
2162
	else if (boldAtom(head))
2163
	  drawBold(expr);
2164
	else if (italicAtom(head))
2165
	  drawItalic(expr);
2166
	else if (plainAtom(head))
2167
	  drawPlain(expr);
2168
	else if (boldItalicAtom(head))
2169
	  drawBoldItalic(expr);
2170
	else if (concatenateAtom(head))
2171
		drawConcatenate(expr);
2172
 
2173
	/* if expression is not a special mathematical notation */
2174
	/* function then just reconstruct expression */
2175
 
2176
	else
2177
		drawExpression(expr);
2178
}
2179
 
2180
/* top-level:  dispatch on whether atom (symbol, string, number, ...) */
2181
/* or formula (some sort of expression) */
2182
 
2183
static BBOX elementBBox(SEXP expr)
2184
{
2185
	if (formulaExpression(expr))
2186
		return formulaBBox(expr);
2187
	else
2188
		return atomBBox(expr);
2189
}
2190
 
2191
static void drawElement(SEXP expr)
2192
{
2193
	if (formulaExpression(expr))
2194
		drawFormula(expr);
2195
	else
2196
		drawAtom(expr);
2197
}
2198
 
257 paul 2199
        /* calculate width of expression */
2200
        /* BBOXes are in INCHES (see metricUnit) */
2201
double GExpressionWidth(SEXP expr, int units)
2202
{
2203
        BBOX exprBBox = elementBBox(expr);
2204
        double w  = exprBBox.width;
2205
        switch(units) {
2206
                case 1: /* user == world */
2207
                        w = ((exprBBox.width / GP->ipr[0]) / GP->fig2dev.bx) / GP->win2fig.bx;
2208
                        break;
2209
                case 2: /* figure */
2210
                        w = (exprBBox.width / GP->ipr[0]) / GP->fig2dev.bx;
2211
                        break;
2212
                case 3: /* inches */
2213
                        w = exprBBox.width;
2214
                        break;
2215
                case 4: /* rasters */
2216
                        w = exprBBox.width / GP->ipr[0];
2217
                        break;
2218
        }
2219
        return w;
2220
}
2221
 
2222
#define ABS(a)  ((a)>=0 ? (a) : -(a))
2223
 
2224
double GExpressionHeight(SEXP expr, int units)
2225
{
2226
        BBOX exprBBox = elementBBox(expr);
2227
        double h = exprBBox.height + exprBBox.depth;
2228
        switch(units) {
2229
                case 1: /* user == world */
2230
                        h = ((h / GP->ipr[1]) / ABS(GP->fig2dev.by)) / GP->win2fig.by;
2231
                        break;
2232
                case 2: /* figure */
2233
                        h = (h / GP->ipr[1]) / ABS(GP->fig2dev.by);
2234
                        break;
2235
                case 3: /* inches */
2236
                        break;
2237
                case 4: /* rasters */
2238
                        h = h / GP->ipr[1];
2239
                        break;
2240
        }
2241
        return h;
2242
}
2243
 
2 r 2244
		/* functions forming the API */
2245
 
2246
void GMathText(double x, double y, SEXP expr, double xc, double yc, double rot)
2247
{
2248
	BBOX expressionBBox;
2249
 
2250
	initFormulaSymbols();
2251
	expressionBBox = elementBBox(expr);
2252
 
2253
	/* NOTE that x and y are in Figure coordinates */
2254
 
2255
	referenceX = xFigtoInch(x);
2256
	referenceY = yFigtoInch(y);
2257
 
2258
	currentX = referenceX - xc * bboxWidth(expressionBBox);
2259
	currentY = referenceY - yc * bboxHeight(expressionBBox);
2260
	currentAngle = rot;
2261
	cosAngle = cos(rot / 90 * half_pi);
2262
	sinAngle = sin(rot / 90 * half_pi);
2263
	drawElement(expr);
2264
}
2265
 
2266
 
2267
#define XINVFMAP(x) ((x - GP->fig2dev.ax)/GP->fig2dev.bx)
2268
#define YINVFMAP(y) ((y - GP->fig2dev.ay)/GP->fig2dev.by)
2269
 
2270
void GMMathText(SEXP str, int side, double line, int outer, double at, int las)
2271
{
2272
	double a, x, y, xadj, yadj;
2273
 
2274
	if (outer) {
2275
		switch (side) {
2276
		case 1:
2277
			x = at;
2278
			y = yChartoNDC(GP->cexbase * GP->mex * (GP->oma[0] - line + 1));
2279
			x = DP->inner2dev.ax + DP->inner2dev.bx * x;
2280
			y = DP->ndc2dev.ay + DP->ndc2dev.by * y;
2281
			a = 0.0;
2282
			xadj = GP->adj;
2283
			yadj = 0.0;
2284
			break;
2285
		case 2:
2286
			x = xChartoNDC(GP->cexbase * GP->mex * (GP->oma[1] - line));
2287
			y = at;
2288
			x = DP->ndc2dev.ax + DP->ndc2dev.bx * x;
2289
			y = DP->inner2dev.ay + DP->inner2dev.by * y;
2290
			a = 90.0;
2291
			xadj = GP->adj;
2292
			yadj = 0.0;
2293
			break;
2294
		case 3:
2295
			x = at;
2296
			y = 1.0 - yChartoNDC(GP->cexbase * GP->mex * (GP->oma[2] - line));
2297
			x = DP->inner2dev.ax + DP->inner2dev.bx * x;
2298
			y = DP->ndc2dev.ay + DP->ndc2dev.by * y;
2299
			a = 0.0;
2300
			xadj = GP->adj;
2301
			yadj = 0.0;
2302
			break;
2303
		case 4:
2304
			x = 1.0 - xChartoNDC(GP->cexbase * GP->mex * (GP->oma[3] - line));
2305
			y = at;
2306
			x = DP->ndc2dev.ax + DP->ndc2dev.bx * x;
2307
			y = DP->inner2dev.ay + DP->inner2dev.by * y;
2308
			a = 90.0;
2309
			xadj = GP->adj;
2310
			yadj = 0.0;
2311
			break;
2312
		}
2313
		x = XINVFMAP(x);
2314
		y = YINVFMAP(y);
2315
		GMathText(x, y, str, xadj, yadj, a);
2316
	}
2317
	else {
2318
		switch (side) {
2319
		case 1:
2320
			if (las == 2) {
2321
				y = GP->plt[2] - yInchtoFig(yChartoInch(GP->cexbase * GP->mex * (line + GP->yLineBias)));
2322
				x = XMAP(at) - xInchtoFig(xChartoInch(GP->cexbase * GP->mex * GP->yLineBias));
2323
				a = 90.0;
2324
				xadj = 1.0;
2325
				yadj = 0.5;
2326
			}
2327
			else {
2328
				y = GP->plt[2] - yInchtoFig(yChartoInch(GP->cexbase * GP->mex * (line + 1 - GP->yLineBias)));
2329
				x = XMAP(at);
2330
				a = 0.0;
2331
				xadj = GP->adj;
2332
				yadj = 0.0;
2333
			}
2334
			break;
2335
		case 2:
2336
			if (las == 1 || las == 2) {
2337
				x = GP->plt[0] - xInchtoFig(xChartoInch(GP->cexbase * GP->mex * (line + GP->yLineBias)));
2338
				y = YMAP(at) + yInchtoFig(yChartoInch(GP->cexbase * GP->mex * GP->yLineBias));
2339
				a = 0.0;
2340
				xadj = 1.0;
2341
				yadj = 0.5;
2342
			}
2343
			else {
2344
				x = GP->plt[0] - xInchtoFig(xChartoInch(GP->cexbase * GP->mex * (line + GP->yLineBias)));
2345
				y = YMAP(at);
2346
				a = 90.0;
2347
				xadj = GP->adj;
2348
				yadj = 0.0;
2349
			}
2350
			break;
2351
		case 3:
2352
			if (las == 2) {
2353
				y = GP->plt[3] + yInchtoFig(yChartoInch(GP->cexbase * GP->mex * (line + GP->yLineBias)));
2354
				x = XMAP(at) - xInchtoFig(xChartoInch(GP->cexbase * GP->mex * GP->yLineBias));
2355
				a = 90.0;
2356
				xadj = 0.0;
2357
				yadj = 0.5;
2358
			}
2359
			else {
2360
				y = GP->plt[3] + yInchtoFig(yChartoInch(GP->cexbase * GP->mex * (line + GP->yLineBias)));
2361
				x = XMAP(at);
2362
				a = 0.0;
2363
				xadj = GP->adj;
2364
				yadj = 0.0;
2365
			}
2366
			break;
2367
		case 4:
2368
			if (las == 1 || las == 2) {
2369
				x = GP->plt[1] + xInchtoFig(xChartoInch(GP->cexbase * GP->mex * (line + GP->yLineBias)));
2370
				y = YMAP(at) + yInchtoFig(yChartoInch(GP->cexbase * GP->mex * GP->yLineBias));
2371
				a = 0.0;
2372
				xadj = 0.0;
2373
				yadj = 0.5;
2374
			}
2375
			else {
2376
				x = GP->plt[1] + xInchtoFig(xChartoInch(GP->cexbase * GP->mex * (line + 1 - GP->yLineBias)));
2377
				y = YMAP(at);
2378
				a = 90.0;
2379
				xadj = GP->adj;
2380
				yadj = 0.0;
2381
			}
2382
			break;
2383
		}
2384
		GMathText(x, y, str, xadj, yadj, a);
2385
	}
2386
}
2387
 
2388
#else
2389
 
2390
void GMMathText(SEXP str, int side, double line, int outer, double at, int las)
2391
{
2392
	error("Can't print math under Windows ... yet\n");
2393
}
2394
 
2395
void GMathText(double x, double y, SEXP expr, double xc, double yc, double rot)
2396
{
2397
	error("Can't print math under Windows ... yet\n");
2398
}
2399
#endif