The R Project SVN R

Rev

Rev 29864 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 29864 Rev 30691
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  Robert Gentleman and Ross Ihaka
3
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
4
 *  Copyright (C) 1997--2001  Robert Gentleman, Ross Ihaka and the
4
 *  Copyright (C) 1997--2001  Robert Gentleman, Ross Ihaka and the
5
 *			      R Development Core Team
5
 *			      R Development Core Team
6
 *  Copyright (C) 2002--2003  The R Foundation
6
 *  Copyright (C) 2002--2004  The R Foundation
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 130... Line 130...
130
	    s = CDR(s);
130
	    s = CDR(s);
131
	}
131
	}
132
    }
132
    }
133
}
133
}
134
 
134
 
-
 
135
/*
-
 
136
 * Extract specified par from list of inline pars
-
 
137
 */
-
 
138
SEXP getInlinePar(SEXP s, char *name)
-
 
139
{
-
 
140
    SEXP result = R_NilValue;
-
 
141
    int found = 0;
-
 
142
    if (isList(s) && !found) {
-
 
143
	while (s != R_NilValue) {
-
 
144
	    if (isList(CAR(s))) {
-
 
145
		result = getInlinePar(CAR(s), name);
-
 
146
		if (result)
-
 
147
		    found = 1;
-
 
148
	    } else
-
 
149
		if (TAG(s) != R_NilValue)
-
 
150
		    if (!strcmp(CHAR(PRINTNAME(TAG(s))), name)) {
-
 
151
			result = CAR(s);
-
 
152
			found = 1;
-
 
153
		    }
-
 
154
	    s = CDR(s);
-
 
155
	}
-
 
156
    }
-
 
157
    return result;
-
 
158
}
-
 
159
 
135
SEXP FixupPch(SEXP pch, int dflt)
160
SEXP FixupPch(SEXP pch, int dflt)
136
{
161
{
137
    int i, n;
162
    int i, n;
138
    SEXP ans = R_NilValue;/* -Wall*/
163
    SEXP ans = R_NilValue;/* -Wall*/
139
 
164
 
Line 371... Line 396...
371
 */
396
 */
372
static void
397
static void
373
GetTextArg(SEXP call, SEXP spec, SEXP *ptxt,
398
GetTextArg(SEXP call, SEXP spec, SEXP *ptxt,
374
	   int *pcol, double *pcex, int *pfont, SEXP *pvfont)
399
	   int *pcol, double *pcex, int *pfont, SEXP *pvfont)
375
{
400
{
376
    int i, n, col, font;
401
    int i, n, col, font, colspecd;
377
    double cex;
402
    double cex;
378
    SEXP txt, vfont, nms;
403
    SEXP txt, vfont, nms;
379
 
404
 
380
    txt	  = R_NilValue;
405
    txt	  = R_NilValue;
381
    vfont = R_NilValue;
406
    vfont = R_NilValue;
382
    cex	  = NA_REAL;
407
    cex	  = NA_REAL;
383
    col	  = NA_INTEGER;
408
    col	  = NA_INTEGER;
-
 
409
    colspecd = 0;
384
    font  = NA_INTEGER;
410
    font  = NA_INTEGER;
385
    PROTECT(txt);
411
    PROTECT(txt);
386
 
412
 
387
    switch (TYPEOF(spec)) {
413
    switch (TYPEOF(spec)) {
388
    case LANGSXP:
414
    case LANGSXP:
Line 411... Line 437...
411
	       for (i = 0; i < n; i++) {
437
	       for (i = 0; i < n; i++) {
412
		if (!strcmp(CHAR(STRING_ELT(nms, i)), "cex")) {
438
		if (!strcmp(CHAR(STRING_ELT(nms, i)), "cex")) {
413
		    cex = asReal(VECTOR_ELT(spec, i));
439
		    cex = asReal(VECTOR_ELT(spec, i));
414
		}
440
		}
415
		else if (!strcmp(CHAR(STRING_ELT(nms, i)), "col")) {
441
		else if (!strcmp(CHAR(STRING_ELT(nms, i)), "col")) {
-
 
442
		    SEXP colsxp = VECTOR_ELT(spec, i);
-
 
443
		    if (!isNAcol(colsxp, 0, LENGTH(colsxp))) {
416
		    col = asInteger(FixupCol(VECTOR_ELT(spec, i), NA_INTEGER));
444
			col = asInteger(FixupCol(colsxp, NA_INTEGER));
-
 
445
			colspecd = 1;
-
 
446
		    }
417
		}
447
		}
418
		else if (!strcmp(CHAR(STRING_ELT(nms, i)), "font")) {
448
		else if (!strcmp(CHAR(STRING_ELT(nms, i)), "font")) {
419
		    font = asInteger(FixupFont(VECTOR_ELT(spec, i), NA_INTEGER));
449
		    font = asInteger(FixupFont(VECTOR_ELT(spec, i), NA_INTEGER));
420
		}
450
		}
421
		else if (!strcmp(CHAR(STRING_ELT(nms, i)), "vfont")) {
451
		else if (!strcmp(CHAR(STRING_ELT(nms, i)), "vfont")) {
Line 447... Line 477...
447
    }
477
    }
448
    UNPROTECT(1);
478
    UNPROTECT(1);
449
    if (txt != R_NilValue) {
479
    if (txt != R_NilValue) {
450
	*ptxt = txt;
480
	*ptxt = txt;
451
	if (R_FINITE(cex))	 *pcex	 = cex;
481
	if (R_FINITE(cex))	 *pcex	 = cex;
452
	if (col != NA_INTEGER)	 *pcol	 = col;
482
	if (colspecd)	         *pcol	 = col;
453
	if (font != NA_INTEGER)	 *pfont	 = font;
483
	if (font != NA_INTEGER)	 *pfont	 = font;
454
	if (vfont != R_NilValue) *pvfont = vfont;
484
	if (vfont != R_NilValue) *pvfont = vfont;
455
    }
485
    }
456
}/* GetTextArg */
486
}/* GetTextArg */
457
 
487
 
Line 1525... Line 1555...
1525
	for (i = 0; i < n; i++) {
1555
	for (i = 0; i < n; i++) {
1526
	    xx = x[i];
1556
	    xx = x[i];
1527
	    yy = y[i];
1557
	    yy = y[i];
1528
	    GConvert(&xx, &yy, USER, DEVICE, dd);
1558
	    GConvert(&xx, &yy, USER, DEVICE, dd);
1529
	    if (R_FINITE(xx) && R_FINITE(yy)
1559
	    if (R_FINITE(xx) && R_FINITE(yy)
1530
		&& (thiscol = INTEGER(col)[i % ncol]) != NA_INTEGER) {
1560
		&& !R_TRANSPARENT(thiscol = INTEGER(col)[i % ncol])) {
1531
		Rf_gpptr(dd)->col = thiscol;
1561
		Rf_gpptr(dd)->col = thiscol;
1532
		GLine(xx, yold, xx, yy, DEVICE, dd);
1562
		GLine(xx, yold, xx, yy, DEVICE, dd);
1533
	    }
1563
	    }
1534
	}
1564
	}
1535
	break;
1565
	break;
Line 1549... Line 1579...
1549
	    yy = y[i];
1579
	    yy = y[i];
1550
	    GConvert(&xx, &yy, USER, DEVICE, dd);
1580
	    GConvert(&xx, &yy, USER, DEVICE, dd);
1551
	    if (R_FINITE(xx) && R_FINITE(yy)) {
1581
	    if (R_FINITE(xx) && R_FINITE(yy)) {
1552
		if (R_FINITE(thiscex = REAL(cex)[i % ncex])
1582
		if (R_FINITE(thiscex = REAL(cex)[i % ncex])
1553
		    && (thispch = INTEGER(pch)[i % npch]) != NA_INTEGER
1583
		    && (thispch = INTEGER(pch)[i % npch]) != NA_INTEGER
1554
		    && (thiscol = INTEGER(col)[i % ncol]) != NA_INTEGER)
1584
		    && !R_TRANSPARENT(thiscol = INTEGER(col)[i % ncol]))
1555
		{
1585
		{
1556
		    Rf_gpptr(dd)->cex = thiscex * Rf_gpptr(dd)->cexbase;
1586
		    Rf_gpptr(dd)->cex = thiscex * Rf_gpptr(dd)->cexbase;
1557
		    Rf_gpptr(dd)->col = thiscol;
1587
		    Rf_gpptr(dd)->col = thiscol;
1558
		    Rf_gpptr(dd)->bg = INTEGER(bg)[i % nbg];
1588
		    Rf_gpptr(dd)->bg = INTEGER(bg)[i % nbg];
1559
		    GSymbol(xx, yy, DEVICE, thispch, dd);
1589
		    GSymbol(xx, yy, DEVICE, thispch, dd);
Line 1754... Line 1784...
1754
 
1784
 
1755
 
1785
 
1756
SEXP do_arrows(SEXP call, SEXP op, SEXP args, SEXP env)
1786
SEXP do_arrows(SEXP call, SEXP op, SEXP args, SEXP env)
1757
{
1787
{
1758
    /* arrows(x0, y0, x1, y1, length, angle, code, col, lty, lwd, xpd) */
1788
    /* arrows(x0, y0, x1, y1, length, angle, code, col, lty, lwd, xpd) */
1759
    SEXP sx0, sx1, sy0, sy1, sxpd, col, lty, lwd;
1789
    SEXP sx0, sx1, sy0, sy1, sxpd, col, rawcol, lty, lwd;
1760
    double *x0, *x1, *y0, *y1;
1790
    double *x0, *x1, *y0, *y1;
1761
    double xx0, yy0, xx1, yy1;
1791
    double xx0, yy0, xx1, yy1;
1762
    double hlength, angle;
1792
    double hlength, angle;
1763
    int code;
1793
    int code;
1764
    int nx0, nx1, ny0, ny1, i, n, ncol, nlty, nlwd, xpd;
1794
    int nx0, nx1, ny0, ny1, i, n, ncol, nlty, nlwd, xpd;
Line 1788... Line 1818...
1788
    code = asInteger(CAR(args));
1818
    code = asInteger(CAR(args));
1789
    if (code == NA_INTEGER || code < 0 || code > 3)
1819
    if (code == NA_INTEGER || code < 0 || code > 3)
1790
	errorcall(call, "invalid arrow head specification");
1820
	errorcall(call, "invalid arrow head specification");
1791
    args = CDR(args);
1821
    args = CDR(args);
1792
 
1822
 
-
 
1823
    /*
-
 
1824
     * Need raw colours to be able to check for NAs
-
 
1825
     * FixupCol converts NAs to fully transparent
-
 
1826
     */
-
 
1827
    rawcol = CAR(args);
1793
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));
1828
    PROTECT(col = FixupCol(rawcol, NA_INTEGER));
1794
    ncol = LENGTH(col);
1829
    ncol = LENGTH(col);
1795
    args = CDR(args);
1830
    args = CDR(args);
1796
 
1831
 
1797
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));
1832
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));
1798
    nlty = length(lty);
1833
    nlty = length(lty);
Line 1830... Line 1865...
1830
	xx1 = x1[i%nx1];
1865
	xx1 = x1[i%nx1];
1831
	yy1 = y1[i%ny1];
1866
	yy1 = y1[i%ny1];
1832
	GConvert(&xx0, &yy0, USER, DEVICE, dd);
1867
	GConvert(&xx0, &yy0, USER, DEVICE, dd);
1833
	GConvert(&xx1, &yy1, USER, DEVICE, dd);
1868
	GConvert(&xx1, &yy1, USER, DEVICE, dd);
1834
	if (R_FINITE(xx0) && R_FINITE(yy0) && R_FINITE(xx1) && R_FINITE(yy1)) {
1869
	if (R_FINITE(xx0) && R_FINITE(yy0) && R_FINITE(xx1) && R_FINITE(yy1)) {
1835
	  Rf_gpptr(dd)->col = INTEGER(col)[i % ncol];
-
 
1836
	    if (Rf_gpptr(dd)->col == NA_INTEGER)
1870
	    if (isNAcol(rawcol, i, ncol))
1837
		Rf_gpptr(dd)->col = Rf_dpptr(dd)->col;
1871
		Rf_gpptr(dd)->col = Rf_dpptr(dd)->col;
-
 
1872
	    else
-
 
1873
		Rf_gpptr(dd)->col = INTEGER(col)[i % ncol];
1838
	    if (nlty == 0 || INTEGER(lty)[i % nlty] == NA_INTEGER)
1874
	    if (nlty == 0 || INTEGER(lty)[i % nlty] == NA_INTEGER)
1839
		Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
1875
		Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
1840
	    else
1876
	    else
1841
		Rf_gpptr(dd)->lty = INTEGER(lty)[i % nlty];
1877
		Rf_gpptr(dd)->lty = INTEGER(lty)[i % nlty];
1842
	    Rf_gpptr(dd)->lwd = REAL(lwd)[i % nlwd];
1878
	    Rf_gpptr(dd)->lwd = REAL(lwd)[i % nlwd];
Line 1956... Line 1992...
1956
SEXP do_text(SEXP call, SEXP op, SEXP args, SEXP env)
1992
SEXP do_text(SEXP call, SEXP op, SEXP args, SEXP env)
1957
{
1993
{
1958
/* text(xy, labels, adj, pos, offset,
1994
/* text(xy, labels, adj, pos, offset,
1959
 *	vfont, cex, col, font, xpd, ...)
1995
 *	vfont, cex, col, font, xpd, ...)
1960
 */
1996
 */
1961
    SEXP sx, sy, sxy, sxpd, txt, adj, pos, cex, col, font, vfont;
1997
    SEXP sx, sy, sxy, sxpd, txt, adj, pos, cex, col, rawcol, font, vfont;
1962
    int i, n, npos, ncex, ncol, nfont, ntxt, xpd;
1998
    int i, n, npos, ncex, ncol, nfont, ntxt, xpd;
1963
    double adjx = 0, adjy = 0, offset = 0.5;
1999
    double adjx = 0, adjy = 0, offset = 0.5;
1964
    double *x, *y;
2000
    double *x, *y;
1965
    double xx, yy;
2001
    double xx, yy;
1966
    Rboolean vectorFonts = FALSE;
2002
    Rboolean vectorFonts = FALSE;
Line 1979... Line 2015...
1979
	txt = coerceVector(txt, EXPRSXP);
2015
	txt = coerceVector(txt, EXPRSXP);
1980
    else if (!isExpression(txt))
2016
    else if (!isExpression(txt))
1981
	txt = coerceVector(txt, STRSXP);
2017
	txt = coerceVector(txt, STRSXP);
1982
    PROTECT(txt);
2018
    PROTECT(txt);
1983
    if (length(txt) <= 0)
2019
    if (length(txt) <= 0)
1984
	errorcall(call, "zero length \"text\" specified");
2020
	errorcall(call, "zero length 'labels'");
1985
    args = CDR(args);
2021
    args = CDR(args);
1986
 
2022
 
1987
    PROTECT(adj = CAR(args));
2023
    PROTECT(adj = CAR(args));
1988
    if (isNull(adj) || (isNumeric(adj) && length(adj) == 0)) {
2024
    if (isNull(adj) || (isNumeric(adj) && length(adj) == 0)) {
1989
	adjx = Rf_gpptr(dd)->adj;
2025
	adjx = Rf_gpptr(dd)->adj;
Line 2029... Line 2065...
2029
 
2065
 
2030
    PROTECT(cex = FixupCex(CAR(args), 1.0));
2066
    PROTECT(cex = FixupCex(CAR(args), 1.0));
2031
    ncex = LENGTH(cex);
2067
    ncex = LENGTH(cex);
2032
    args = CDR(args);
2068
    args = CDR(args);
2033
 
2069
 
-
 
2070
    rawcol = CAR(args);
2034
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));
2071
    PROTECT(col = FixupCol(rawcol, NA_INTEGER));
2035
    ncol = LENGTH(col);
2072
    ncol = LENGTH(col);
2036
    args = CDR(args);
2073
    args = CDR(args);
2037
 
2074
 
2038
    PROTECT(font = FixupFont(CAR(args), NA_INTEGER));
2075
    PROTECT(font = FixupFont(CAR(args), NA_INTEGER));
2039
    nfont = LENGTH(font);
2076
    nfont = LENGTH(font);
Line 2060... Line 2097...
2060
    for (i = 0; i < n; i++) {
2097
    for (i = 0; i < n; i++) {
2061
	xx = x[i % n];
2098
	xx = x[i % n];
2062
	yy = y[i % n];
2099
	yy = y[i % n];
2063
	GConvert(&xx, &yy, USER, INCHES, dd);
2100
	GConvert(&xx, &yy, USER, INCHES, dd);
2064
	if (R_FINITE(xx) && R_FINITE(yy)) {
2101
	if (R_FINITE(xx) && R_FINITE(yy)) {
2065
	    if (ncol && INTEGER(col)[i % ncol] != NA_INTEGER)
2102
	    if (ncol && !isNAcol(rawcol, i, ncol))
2066
		Rf_gpptr(dd)->col = INTEGER(col)[i % ncol];
2103
		Rf_gpptr(dd)->col = INTEGER(col)[i % ncol];
2067
	    else
2104
	    else
2068
		Rf_gpptr(dd)->col = Rf_dpptr(dd)->col;
2105
		Rf_gpptr(dd)->col = Rf_dpptr(dd)->col;
2069
	    if (ncex && R_FINITE(REAL(cex)[i%ncex]))
2106
	    if (ncex && R_FINITE(REAL(cex)[i%ncex]))
2070
		Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * REAL(cex)[i % ncex];
2107
		Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * REAL(cex)[i % ncex];
Line 2241... Line 2278...
2241
	 ...) */
2278
	 ...) */
2242
 
2279
 
2243
SEXP do_mtext(SEXP call, SEXP op, SEXP args, SEXP env)
2280
SEXP do_mtext(SEXP call, SEXP op, SEXP args, SEXP env)
2244
{
2281
{
2245
    SEXP text, side, line, outer, at, adj, cex, col, font, vfont, string;
2282
    SEXP text, side, line, outer, at, adj, cex, col, font, vfont, string;
-
 
2283
    SEXP rawcol;
2246
    int ntext, nside, nline, nouter, nat, nadj, ncex, ncol, nfont;
2284
    int ntext, nside, nline, nouter, nat, nadj, ncex, ncol, nfont;
2247
    Rboolean dirtyplot = FALSE, gpnewsave = FALSE, dpnewsave = FALSE;
2285
    Rboolean dirtyplot = FALSE, gpnewsave = FALSE, dpnewsave = FALSE;
2248
    Rboolean vectorFonts = FALSE;
2286
    Rboolean vectorFonts = FALSE;
2249
    int i, n, fontsave, colsave;
2287
    int i, n, fontsave, colsave;
2250
    double cexsave;
2288
    double cexsave;
Line 2310... Line 2348...
2310
    if (ncex <= 0) errorcall(call, "zero length \"cex\" specified");
2348
    if (ncex <= 0) errorcall(call, "zero length \"cex\" specified");
2311
    if (n < ncex) n = ncex;
2349
    if (n < ncex) n = ncex;
2312
    args = CDR(args);
2350
    args = CDR(args);
2313
 
2351
 
2314
    /* Arg8 : col */
2352
    /* Arg8 : col */
-
 
2353
    rawcol = CAR(args);
2315
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));
2354
    PROTECT(col = FixupCol(rawcol, NA_INTEGER));
2316
    ncol = length(col);
2355
    ncol = length(col);
2317
    if (ncol <= 0) errorcall(call, "zero length \"col\" specified");
2356
    if (ncol <= 0) errorcall(call, "zero length \"col\" specified");
2318
    if (n < ncol) n = ncol;
2357
    if (n < ncol) n = ncol;
2319
    args = CDR(args);
2358
    args = CDR(args);
2320
 
2359
 
Line 2372... Line 2411...
2372
	/* by mfrow / mfcol specs here.	 I.e. don't */
2411
	/* by mfrow / mfcol specs here.	 I.e. don't */
2373
	/* Rf_gpptr(dd)->cexbase. */
2412
	/* Rf_gpptr(dd)->cexbase. */
2374
	if (R_FINITE(cexval)) Rf_gpptr(dd)->cex = cexval;
2413
	if (R_FINITE(cexval)) Rf_gpptr(dd)->cex = cexval;
2375
	else cexval = cexsave;
2414
	else cexval = cexsave;
2376
	Rf_gpptr(dd)->font = (fontval == NA_INTEGER) ? fontsave : fontval;
2415
	Rf_gpptr(dd)->font = (fontval == NA_INTEGER) ? fontsave : fontval;
-
 
2416
	if (isNAcol(rawcol, i, ncol))
2377
	Rf_gpptr(dd)->col = (colval == NA_INTEGER) ? colsave : colval;
2417
	    Rf_gpptr(dd)->col = colsave;
-
 
2418
	else
-
 
2419
	    Rf_gpptr(dd)->col = colval;
2378
	Rf_gpptr(dd)->adj = ComputeAdjValue(adjval, sideval, Rf_gpptr(dd)->las);
2420
	Rf_gpptr(dd)->adj = ComputeAdjValue(adjval, sideval, Rf_gpptr(dd)->las);
2379
	atval = ComputeAtValue(atval, Rf_gpptr(dd)->adj, sideval, Rf_gpptr(dd)->las,
2421
	atval = ComputeAtValue(atval, Rf_gpptr(dd)->adj, sideval, Rf_gpptr(dd)->las,
2380
			       outerval, dd);
2422
			       outerval, dd);
2381
 
2423
 
2382
	if (vectorFonts) {
2424
	if (vectorFonts) {
Line 2853... Line 2895...
2853
{
2895
{
2854
/*     box(which="plot", lty="solid", ...)
2896
/*     box(which="plot", lty="solid", ...)
2855
       --- which is coded, 1 = plot, 2 = figure, 3 = inner, 4 = outer.
2897
       --- which is coded, 1 = plot, 2 = figure, 3 = inner, 4 = outer.
2856
*/
2898
*/
2857
    int which, col;
2899
    int which, col;
-
 
2900
    SEXP colsxp, fgsxp;
2858
    SEXP originalArgs = args;
2901
    SEXP originalArgs = args;
2859
    DevDesc *dd = CurrentDevice();
2902
    DevDesc *dd = CurrentDevice();
2860
 
2903
 
2861
    GCheckState(dd);
2904
    GCheckState(dd);
2862
    GSavePars(dd);
2905
    GSavePars(dd);
2863
    which = asInteger(CAR(args)); args = CDR(args);
2906
    which = asInteger(CAR(args)); args = CDR(args);
2864
    if (which < 1 || which > 4)
2907
    if (which < 1 || which > 4)
2865
	errorcall(call, "invalid \"which\" specification");
2908
	errorcall(call, "invalid \"which\" specification");
-
 
2909
    /*
-
 
2910
     * If specified non-NA col then use that, else ...
-
 
2911
     *
2866
    col= Rf_gpptr(dd)->col;	Rf_gpptr(dd)->col= NA_INTEGER;
2912
     * if specified non-NA fg then use that, else ...
-
 
2913
     *
-
 
2914
     * else use par("col")
-
 
2915
     */
2867
    Rf_gpptr(dd)->fg = NA_INTEGER;
2916
    col= Rf_gpptr(dd)->col;
2868
    ProcessInlinePars(args, dd, call);
2917
    ProcessInlinePars(args, dd, call);
2869
    if (Rf_gpptr(dd)->col == NA_INTEGER) {/* col := 'fg' or original 'col' */
2918
    colsxp = getInlinePar(args, "col");
-
 
2919
    if (isNAcol(colsxp, 0, 1)) {
-
 
2920
	fgsxp = getInlinePar(args, "fg");
2870
	if (Rf_gpptr(dd)->fg == NA_INTEGER)
2921
	if (isNAcol(fgsxp, 0, 1))
2871
	    Rf_gpptr(dd)->col = col;
2922
	    Rf_gpptr(dd)->col = col;
2872
	else
2923
	else
2873
	    Rf_gpptr(dd)->col = Rf_gpptr(dd)->fg;
2924
	    Rf_gpptr(dd)->col = Rf_gpptr(dd)->fg;
2874
    }
2925
    }
2875
    /* override par("xpd") and force clipping to device region */
2926
    /* override par("xpd") and force clipping to device region */
Line 3145... Line 3196...
3145
 
3196
 
3146
	return ans;
3197
	return ans;
3147
    }
3198
    }
3148
}
3199
}
3149
 
3200
 
3150
SEXP do_strheight(SEXP call, SEXP op, SEXP args, SEXP env)
3201
/* strheight(str, units)  ||  strwidth(str, units) */
3151
{
-
 
3152
    /* strheight(str, units) */
3202
#define DO_STR_DIM(KIND) 						\
-
 
3203
{									\
3153
    SEXP ans, str, ch;
3204
    SEXP ans, str, ch;							\
3154
    int i, n, units;
3205
    int i, n, units;							\
3155
    double cex, cexsave;
3206
    double cex, cexsave;						\
3156
    DevDesc *dd = CurrentDevice();
3207
    DevDesc *dd = CurrentDevice();					\
3157
 
3208
									\
3158
    checkArity(op,args);
3209
    checkArity(op, args);						\
3159
    GCheckState(dd);
3210
    GCheckState(dd);							\
3160
 
3211
									\
3161
    str = CAR(args);
3212
    str = CAR(args);							\
3162
    if (isSymbol(str) || isLanguage(str))
3213
    if (isSymbol(str) || isLanguage(str))				\
3163
	str = coerceVector(str, EXPRSXP);
3214
	str = coerceVector(str, EXPRSXP);				\
3164
    else if (!isExpression(str))
3215
    else if (!isExpression(str))					\
3165
	str = coerceVector(str, STRSXP);
3216
	str = coerceVector(str, STRSXP);				\
3166
    PROTECT(str);
3217
    PROTECT(str);							\
3167
    args = CDR(args);
3218
    args = CDR(args);							\
3168
 
3219
									\
3169
    if ((units = asInteger(CAR(args))) == NA_INTEGER || units < 0)
3220
    if ((units = asInteger(CAR(args))) == NA_INTEGER || units < 0)	\
3170
	errorcall(call, "invalid units");
3221
	errorcall(call, "invalid units");				\
3171
    args = CDR(args);
3222
    args = CDR(args);							\
3172
 
3223
									\
3173
    if (isNull(CAR(args)))
3224
    if (isNull(CAR(args)))						\
3174
	cex = Rf_gpptr(dd)->cex;
3225
	cex = Rf_gpptr(dd)->cex;					\
3175
    else if (!R_FINITE(cex = asReal(CAR(args))) || cex <= 0.0)
3226
    else if (!R_FINITE(cex = asReal(CAR(args))) || cex <= 0.0)		\
3176
	errorcall(call, "invalid cex value");
3227
	errorcall(call, "invalid cex value");				\
3177
 
3228
									\
3178
    n = LENGTH(str);
3229
    n = LENGTH(str);							\
3179
    PROTECT(ans = allocVector(REALSXP, n));
3230
    PROTECT(ans = allocVector(REALSXP, n));				\
3180
    cexsave = Rf_gpptr(dd)->cex;
3231
    cexsave = Rf_gpptr(dd)->cex;					\
3181
    Rf_gpptr(dd)->cex = cex * Rf_gpptr(dd)->cexbase;
3232
    Rf_gpptr(dd)->cex = cex * Rf_gpptr(dd)->cexbase;			\
3182
    for (i = 0; i < n; i++)
3233
    for (i = 0; i < n; i++)						\
3183
	if (isExpression(str))
3234
	if (isExpression(str))						\
3184
	    REAL(ans)[i] = GExpressionHeight(VECTOR_ELT(str, i),
3235
	    REAL(ans)[i] = GExpression ## KIND(VECTOR_ELT(str, i),	\
3185
					     GMapUnits(units), dd);
3236
					     GMapUnits(units), dd);	\
3186
	else {
3237
	else {								\
3187
	    ch = STRING_ELT(str, i);
3238
	    ch = STRING_ELT(str, i);					\
3188
	    REAL(ans)[i] = (ch == NA_STRING) ? 0.0 :
3239
	    REAL(ans)[i] = (ch == NA_STRING) ? 0.0 :			\
3189
		GStrHeight(CHAR(ch), GMapUnits(units), dd);
3240
		GStr ## KIND(CHAR(ch), GMapUnits(units), dd);		\
3190
	}
3241
	}								\
3191
    Rf_gpptr(dd)->cex = cexsave;
3242
    Rf_gpptr(dd)->cex = cexsave;					\
3192
    UNPROTECT(2);
3243
    UNPROTECT(2);							\
3193
    return ans;
3244
    return ans;								\
3194
}
3245
}
3195
 
3246
 
-
 
3247
SEXP do_strheight(SEXP call, SEXP op, SEXP args, SEXP env)
-
 
3248
DO_STR_DIM(Height)
3196
 
3249
 
3197
SEXP do_strwidth(SEXP call, SEXP op, SEXP args, SEXP env)
3250
SEXP do_strwidth (SEXP call, SEXP op, SEXP args, SEXP env)
3198
{
-
 
3199
    /* strwidth(str, units) */
-
 
3200
    SEXP ans, str, ch;
-
 
3201
    int i, n, units;
-
 
3202
    double cex, cexsave;
-
 
3203
    DevDesc *dd = CurrentDevice();
-
 
3204
 
-
 
3205
    checkArity(op, args);
-
 
3206
    GCheckState(dd);
-
 
3207
 
-
 
3208
    str = CAR(args);
-
 
3209
    if (isSymbol(str) || isLanguage(str))
-
 
3210
	str = coerceVector(str, EXPRSXP);
-
 
3211
    else if (!isExpression(str))
-
 
3212
	str = coerceVector(str, STRSXP);
-
 
3213
    PROTECT(str);
3251
DO_STR_DIM(Width)
3214
 
-
 
3215
    args = CDR(args);
-
 
3216
 
3252
 
3217
    if ((units = asInteger(CAR(args))) == NA_INTEGER || units < 0)
-
 
3218
	errorcall(call, "invalid units");
-
 
3219
    args = CDR(args);
3253
#undef DO_STR_DIM
3220
 
3254
 
3221
    if (isNull(CAR(args)))
-
 
3222
	cex = Rf_gpptr(dd)->cex;
-
 
3223
    else if (!R_FINITE(cex = asReal(CAR(args))) || cex <= 0.0)
-
 
3224
	errorcall(call, "invalid cex value");
-
 
3225
 
3255
 
3226
    n = LENGTH(str);
-
 
3227
    PROTECT(ans = allocVector(REALSXP, n));
-
 
3228
    cexsave = Rf_gpptr(dd)->cex;
-
 
3229
    Rf_gpptr(dd)->cex = cex * Rf_gpptr(dd)->cexbase;
-
 
3230
    for (i = 0; i < n; i++)
-
 
3231
	if (isExpression(str))
-
 
3232
	    REAL(ans)[i] = GExpressionWidth(VECTOR_ELT(str, i),
-
 
3233
					    GMapUnits(units), dd);
-
 
3234
	else {
-
 
3235
	    ch = STRING_ELT(str, i);
-
 
3236
	    REAL(ans)[i] = (ch == NA_STRING) ? 0.0 :
-
 
3237
		GStrWidth(CHAR(ch), GMapUnits(units), dd);
-
 
3238
	}
-
 
3239
    Rf_gpptr(dd)->cex = cexsave;
-
 
3240
    UNPROTECT(2);
-
 
3241
    return ans;
-
 
3242
}
-
 
3243
 
-
 
3244
static int dnd_n;
-
 
3245
static int *dnd_lptr;
3256
static int *dnd_lptr;
3246
static int *dnd_rptr;
3257
static int *dnd_rptr;
3247
static double *dnd_hght;
3258
static double *dnd_hght;
3248
static double *dnd_xpos;
3259
static double *dnd_xpos;
3249
static double dnd_hang;
3260
static double dnd_hang;
Line 3251... Line 3262...
3251
static SEXP *dnd_llabels;
3262
static SEXP *dnd_llabels;
3252
 
3263
 
3253
 
3264
 
3254
static void drawdend(int node, double *x, double *y, DevDesc *dd)
3265
static void drawdend(int node, double *x, double *y, DevDesc *dd)
3255
{
3266
{
-
 
3267
/* Recursive function for 'hclust' dendrogram drawing:
-
 
3268
 * Do left + Do right + Do myself
-
 
3269
 * "do" : 1) label leafs (if there are) and __
-
 
3270
 *        2) find coordinates to draw the  | |
-
 
3271
 *        3) return (*x,*y) of "my anchor"
-
 
3272
 */
3256
    double xl, xr, yl, yr;
3273
    double xl, xr, yl, yr;
3257
    double xx[4], yy[4];
3274
    double xx[4], yy[4];
3258
    int k;
3275
    int k;
-
 
3276
 
3259
    *y = dnd_hght[node-1];
3277
    *y = dnd_hght[node-1];
-
 
3278
    /* left part  */
3260
    k = dnd_lptr[node-1];
3279
    k = dnd_lptr[node-1];
3261
    if (k > 0) drawdend(k, &xl, &yl, dd);
3280
    if (k > 0) drawdend(k, &xl, &yl, dd);
3262
    else {
3281
    else {
3263
	xl = dnd_xpos[-k-1];
3282
	xl = dnd_xpos[-k-1];
3264
	if (dnd_hang >= 0) yl = *y - dnd_hang;
3283
	yl = (dnd_hang >= 0) ? *y - dnd_hang : 0;
3265
	else yl = 0;
-
 
3266
	if(dnd_llabels[-k-1] != NA_STRING)
3284
	if(dnd_llabels[-k-1] != NA_STRING)
3267
	    GText(xl, yl-dnd_offset, USER, CHAR(dnd_llabels[-k-1]),
3285
	    GText(xl, yl-dnd_offset, USER, CHAR(dnd_llabels[-k-1]),
3268
		  1.0, 0.3, 90.0, dd);
3286
		  1.0, 0.3, 90.0, dd);
3269
    }
3287
    }
-
 
3288
    /* right part */
3270
    k = dnd_rptr[node-1];
3289
    k = dnd_rptr[node-1];
3271
    if (k > 0) drawdend(k, &xr, &yr, dd);
3290
    if (k > 0) drawdend(k, &xr, &yr, dd);
3272
    else {
3291
    else {
3273
	xr = dnd_xpos[-k-1];
3292
	xr = dnd_xpos[-k-1];
3274
	if (dnd_hang >= 0) yr = *y - dnd_hang;
3293
	yr = (dnd_hang >= 0) ? *y - dnd_hang : 0;
3275
	else yr = 0;
-
 
3276
	if(dnd_llabels[-k-1] != NA_STRING)
3294
	if(dnd_llabels[-k-1] != NA_STRING)
3277
	    GText(xr, yr-dnd_offset, USER, CHAR(dnd_llabels[-k-1]),
3295
	    GText(xr, yr-dnd_offset, USER, CHAR(dnd_llabels[-k-1]),
3278
		  1.0, 0.3, 90.0, dd);
3296
		  1.0, 0.3, 90.0, dd);
3279
    }
3297
    }
3280
    xx[0] = xl; yy[0] = yl;
3298
    xx[0] = xl; yy[0] = yl;
Line 3287... Line 3305...
3287
 
3305
 
3288
 
3306
 
3289
SEXP do_dend(SEXP call, SEXP op, SEXP args, SEXP env)
3307
SEXP do_dend(SEXP call, SEXP op, SEXP args, SEXP env)
3290
{
3308
{
3291
    double x, y;
3309
    double x, y;
-
 
3310
    int n;
-
 
3311
 
3292
    SEXP originalArgs;
3312
    SEXP originalArgs;
3293
    DevDesc *dd;
3313
    DevDesc *dd;
3294
 
3314
 
3295
    dd = CurrentDevice();
3315
    dd = CurrentDevice();
3296
    GCheckState(dd);
3316
    GCheckState(dd);
3297
 
3317
 
3298
    originalArgs = args;
3318
    originalArgs = args;
3299
    if (length(args) < 6)
3319
    if (length(args) < 6)
3300
	errorcall(call, "too few arguments");
3320
	errorcall(call, "too few arguments");
3301
 
3321
 
-
 
3322
    /* n */
3302
    dnd_n = asInteger(CAR(args));
3323
    n = asInteger(CAR(args));
3303
    if (dnd_n == NA_INTEGER || dnd_n < 2)
3324
    if (n == NA_INTEGER || n < 2)
3304
	goto badargs;
3325
	goto badargs;
3305
    args = CDR(args);
3326
    args = CDR(args);
3306
 
3327
 
-
 
3328
    /* merge */
3307
    if (TYPEOF(CAR(args)) != INTSXP || length(CAR(args)) != 2*dnd_n)
3329
    if (TYPEOF(CAR(args)) != INTSXP || length(CAR(args)) != 2*n)
3308
	goto badargs;
3330
	goto badargs;
3309
    dnd_lptr = &(INTEGER(CAR(args))[0]);
3331
    dnd_lptr = &(INTEGER(CAR(args))[0]);
3310
    dnd_rptr = &(INTEGER(CAR(args))[dnd_n]);
3332
    dnd_rptr = &(INTEGER(CAR(args))[n]);
3311
    args = CDR(args);
3333
    args = CDR(args);
3312
 
3334
 
-
 
3335
    /* height */
3313
    if (TYPEOF(CAR(args)) != REALSXP || length(CAR(args)) != dnd_n)
3336
    if (TYPEOF(CAR(args)) != REALSXP || length(CAR(args)) != n)
3314
	goto badargs;
3337
	goto badargs;
3315
    dnd_hght = REAL(CAR(args));
3338
    dnd_hght = REAL(CAR(args));
3316
    args = CDR(args);
3339
    args = CDR(args);
3317
 
3340
 
-
 
3341
    /* ord = order(x$order) */
3318
    if (TYPEOF(CAR(args)) != REALSXP || length(CAR(args)) != dnd_n+1)
3342
    if (length(CAR(args)) != n+1)
3319
	goto badargs;
3343
	goto badargs;
3320
    dnd_xpos = REAL(CAR(args));
3344
    dnd_xpos = REAL(coerceVector(CAR(args),REALSXP));
3321
    args = CDR(args);
3345
    args = CDR(args);
3322
 
3346
 
-
 
3347
    /* hang */
3323
    dnd_hang = asReal(CAR(args));
3348
    dnd_hang = asReal(CAR(args));
3324
    if (!R_FINITE(dnd_hang))
3349
    if (!R_FINITE(dnd_hang))
3325
	goto badargs;
3350
	goto badargs;
3326
    dnd_hang = dnd_hang * (dnd_hght[dnd_n-1] - dnd_hght[0]);
3351
    dnd_hang = dnd_hang * (dnd_hght[n-1] - dnd_hght[0]);
3327
    args = CDR(args);
3352
    args = CDR(args);
3328
 
3353
 
-
 
3354
    /* labels */
3329
    if (TYPEOF(CAR(args)) != STRSXP || length(CAR(args)) != dnd_n+1)
3355
    if (TYPEOF(CAR(args)) != STRSXP || length(CAR(args)) != n+1)
3330
	goto badargs;
3356
	goto badargs;
3331
    dnd_llabels = STRING_PTR(CAR(args));
3357
    dnd_llabels = STRING_PTR(CAR(args));
3332
    args = CDR(args);
3358
    args = CDR(args);
3333
 
3359
 
3334
    GSavePars(dd);
3360
    GSavePars(dd);
Line 3340... Line 3366...
3340
    /* NOTE: don't override to _reduce_ clipping region */
3366
    /* NOTE: don't override to _reduce_ clipping region */
3341
    if (Rf_gpptr(dd)->xpd < 1)
3367
    if (Rf_gpptr(dd)->xpd < 1)
3342
	Rf_gpptr(dd)->xpd = 1;
3368
	Rf_gpptr(dd)->xpd = 1;
3343
 
3369
 
3344
    GMode(1, dd);
3370
    GMode(1, dd);
3345
    drawdend(dnd_n, &x, &y, dd);
3371
    drawdend(n, &x, &y, dd);
3346
    GMode(0, dd);
3372
    GMode(0, dd);
3347
    GRestorePars(dd);
3373
    GRestorePars(dd);
3348
    /* NOTE: only record operation if no "error"  */
3374
    /* NOTE: only record operation if no "error"  */
3349
    if (GRecording(call))
3375
    if (GRecording(call))
3350
	recordGraphicOperation(op, originalArgs, dd);
3376
	recordGraphicOperation(op, originalArgs, dd);
Line 3364... Line 3390...
3364
    DevDesc *dd;
3390
    DevDesc *dd;
3365
 
3391
 
3366
    dd = CurrentDevice();
3392
    dd = CurrentDevice();
3367
    GCheckState(dd);
3393
    GCheckState(dd);
3368
    originalArgs = args;
3394
    originalArgs = args;
3369
    if (length(args) < 6)
3395
    if (length(args) < 5)
3370
	errorcall(call, "too few arguments");
3396
	errorcall(call, "too few arguments");
3371
    n = asInteger(CAR(args));
3397
    n = asInteger(CAR(args));
3372
    if (n == NA_INTEGER || n < 2)
3398
    if (n == NA_INTEGER || n < 2)
3373
	goto badargs;
3399
	goto badargs;
3374
    args = CDR(args);
3400
    args = CDR(args);
3375
    if (TYPEOF(CAR(args)) != INTSXP || length(CAR(args)) != 2 * n)
3401
    if (TYPEOF(CAR(args)) != INTSXP || length(CAR(args)) != 2 * n)
3376
	goto badargs;
3402
	goto badargs;
3377
    merge = CAR(args);
3403
    merge = CAR(args);
-
 
3404
 
3378
    args = CDR(args);
3405
    args = CDR(args);
3379
    if (TYPEOF(CAR(args)) != REALSXP || length(CAR(args)) != n)
3406
    if (TYPEOF(CAR(args)) != REALSXP || length(CAR(args)) != n)
3380
	goto badargs;
3407
	goto badargs;
3381
    height = CAR(args);
3408
    height = CAR(args);
3382
    args = CDR(args);
-
 
3383
    if (TYPEOF(CAR(args)) != REALSXP || length(CAR(args)) != n + 1)
-
 
3384
	goto badargs;
3409
 
3385
    dnd_xpos = REAL(CAR(args));
-
 
3386
    args = CDR(args);
3410
    args = CDR(args);
3387
    dnd_hang = asReal(CAR(args));
3411
    dnd_hang = asReal(CAR(args));
3388
    if (!R_FINITE(dnd_hang))
3412
    if (!R_FINITE(dnd_hang))
3389
	goto badargs;
3413
	goto badargs;
-
 
3414
 
3390
    args = CDR(args);
3415
    args = CDR(args);
3391
    if (TYPEOF(CAR(args)) != STRSXP || length(CAR(args)) != n + 1)
3416
    if (TYPEOF(CAR(args)) != STRSXP || length(CAR(args)) != n + 1)
3392
	goto badargs;
3417
	goto badargs;
3393
 
-
 
3394
    llabels = CAR(args);
3418
    llabels = CAR(args);
-
 
3419
 
3395
    args = CDR(args);
3420
    args = CDR(args);
3396
    GSavePars(dd);
3421
    GSavePars(dd);
3397
    ProcessInlinePars(args, dd, call);
3422
    ProcessInlinePars(args, dd, call);
3398
    Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * Rf_gpptr(dd)->cex;
3423
    Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * Rf_gpptr(dd)->cex;
3399
    dnd_offset = GStrWidth("m", INCHES, dd);
3424
    dnd_offset = GStrWidth("m", INCHES, dd);
Line 3414... Line 3439...
3414
    for (i = 0; i < n; i++) {
3439
    for (i = 0; i < n; i++) {
3415
	str = STRING_ELT(llabels, i);
3440
	str = STRING_ELT(llabels, i);
3416
	ll[i] = (str == NA_STRING) ? 0.0 :
3441
	ll[i] = (str == NA_STRING) ? 0.0 :
3417
	    GStrWidth(CHAR(str), INCHES, dd) + dnd_offset;
3442
	    GStrWidth(CHAR(str), INCHES, dd) + dnd_offset;
3418
    }
3443
    }
-
 
3444
 
-
 
3445
    imax = -1; yval = -DBL_MAX;
3419
    if (dnd_hang >= 0) {
3446
    if (dnd_hang >= 0) {
3420
	ymin = ymax - (1 + dnd_hang) * (ymax - ymin);
3447
	ymin = ymax - (1 + dnd_hang) * (ymax - ymin);
3421
	yrange = ymax - ymin;
3448
	yrange = ymax - ymin;
3422
	/* determine leaf heights */
3449
	/* determine leaf heights */
3423
	for (i = 0; i < n; i++) {
3450
	for (i = 0; i < n; i++) {
Line 3427... Line 3454...
3427
		y[-dnd_rptr[i] - 1] = REAL(height)[i];
3454
		y[-dnd_rptr[i] - 1] = REAL(height)[i];
3428
	}
3455
	}
3429
	/* determine the most extreme label depth */
3456
	/* determine the most extreme label depth */
3430
	/* assuming that we are using the full plot */
3457
	/* assuming that we are using the full plot */
3431
	/* window for the tree itself */
3458
	/* window for the tree itself */
3432
	imax = -1;
-
 
3433
	yval = -DBL_MAX;
-
 
3434
	for (i = 0; i < n; i++) {
3459
	for (i = 0; i < n; i++) {
3435
	    tmp = ((ymax - y[i]) / yrange) * pin + ll[i];
3460
	    tmp = ((ymax - y[i]) / yrange) * pin + ll[i];
3436
	    if (tmp > yval) {
3461
	    if (tmp > yval) {
3437
		yval = tmp;
3462
		yval = tmp;
3438
		imax = i;
3463
		imax = i;
3439
	    }
3464
	    }
3440
	}
3465
	}
3441
    }
3466
    }
3442
    else {
3467
    else {
3443
	ymin = 0;
-
 
3444
	yrange = ymax;
3468
	yrange = ymax;
3445
	imax = -1;
-
 
3446
	yval = -DBL_MAX;
-
 
3447
	for (i = 0; i < n; i++) {
3469
	for (i = 0; i < n; i++) {
3448
	    tmp = pin + ll[i];
3470
	    tmp = pin + ll[i];
3449
	    if (tmp > yval) {
3471
	    if (tmp > yval) {
3450
		yval = tmp;
3472
		yval = tmp;
3451
		imax = i;
3473
		imax = i;
3452
	    }
3474
	    }
3453
	}
3475
	}
3454
    }
3476
    }
3455
    /* now determine how much to scale */
3477
    /* now determine how much to scale */
3456
    ymin = ymax - (pin/(pin - ll[imax])) * (ymax - ymin);
3478
    ymin = ymax - (pin/(pin - ll[imax])) * yrange;
3457
    GScale(1.0, n+1.0, 1, dd);
3479
    GScale(1.0, n+1.0, 1 /* x */, dd);
3458
    GScale(ymin, ymax, 2, dd);
3480
    GScale(ymin, ymax, 2 /* y */, dd);
3459
    GMapWin2Fig(dd);
3481
    GMapWin2Fig(dd);
3460
    GRestorePars(dd);
3482
    GRestorePars(dd);
3461
    /* NOTE: only record operation if no "error"  */
3483
    /* NOTE: only record operation if no "error"  */
3462
    if (GRecording(call))
3484
    if (GRecording(call))
3463
	recordGraphicOperation(op, originalArgs, dd);
3485
	recordGraphicOperation(op, originalArgs, dd);