The R Project SVN R

Rev

Rev 29864 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 29864 Rev 30691
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.
12
 *
12
 *
13
 *  This program is distributed in the hope that it will be useful,
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
16
 *  GNU General Public License for more details.
17
 *
17
 *
18
 *  A copy of the GNU General Public License is available via WWW at
18
 *  A copy of the GNU General Public License is available via WWW at
19
 *  http://www.gnu.org/copyleft/gpl.html.  You can also obtain it by
19
 *  http://www.gnu.org/copyleft/gpl.html.  You can also obtain it by
20
 *  writing to the Free Software Foundation, Inc., 59 Temple Place,
20
 *  writing to the Free Software Foundation, Inc., 59 Temple Place,
21
 *  Suite 330, Boston, MA  02111-1307  USA.
21
 *  Suite 330, Boston, MA  02111-1307  USA.
22
 */
22
 */
23
 
23
 
24
#ifdef HAVE_CONFIG_H
24
#ifdef HAVE_CONFIG_H
25
#include <config.h>
25
#include <config.h>
26
#endif
26
#endif
27
 
27
 
28
#include <Defn.h>
28
#include <Defn.h>
29
#include <Rmath.h>
29
#include <Rmath.h>
30
#include <Graphics.h>
30
#include <Graphics.h>
31
#include <Rdevices.h>
31
#include <Rdevices.h>
32
#include <Print.h>
32
#include <Print.h>
33
 
33
 
34
#ifndef HAVE_HYPOT
34
#ifndef HAVE_HYPOT
35
# define hypot pythag
35
# define hypot pythag
36
#endif
36
#endif
37
 
37
 
38
 
38
 
39
void NewFrameConfirm(void)
39
void NewFrameConfirm(void)
40
{
40
{
41
    unsigned char buf[16];
41
    unsigned char buf[16];
42
    R_ReadConsole("Hit <Return> to see next plot: ", buf, 16, 0);
42
    R_ReadConsole("Hit <Return> to see next plot: ", buf, 16, 0);
43
}
43
}
44
 
44
 
45
	/* Remember: +1 and/or -1 because C arrays are */
45
	/* Remember: +1 and/or -1 because C arrays are */
46
	/* zero-based and R-vectors are one-based. */
46
	/* zero-based and R-vectors are one-based. */
47
 
47
 
48
#define checkArity_length					\
48
#define checkArity_length					\
49
    checkArity(op, args);					\
49
    checkArity(op, args);					\
50
    if(!LENGTH(CAR(args)))					\
50
    if(!LENGTH(CAR(args)))					\
51
	errorcall(call, "argument must have positive length")
51
	errorcall(call, "argument must have positive length")
52
 
52
 
53
 
53
 
54
SEXP do_devcontrol(SEXP call, SEXP op, SEXP args, SEXP env)
54
SEXP do_devcontrol(SEXP call, SEXP op, SEXP args, SEXP env)
55
{
55
{
56
    int listFlag;
56
    int listFlag;
57
 
57
 
58
    checkArity(op, args);
58
    checkArity(op, args);
59
    listFlag = asLogical(CAR(args));
59
    listFlag = asLogical(CAR(args));
60
    if(listFlag == NA_LOGICAL) errorcall(call, "invalid argument");
60
    if(listFlag == NA_LOGICAL) errorcall(call, "invalid argument");
61
    if(listFlag)
61
    if(listFlag)
62
	enableDisplayList(CurrentDevice());
62
	enableDisplayList(CurrentDevice());
63
    else
63
    else
64
	inhibitDisplayList(CurrentDevice());
64
	inhibitDisplayList(CurrentDevice());
65
    return ScalarLogical(listFlag);
65
    return ScalarLogical(listFlag);
66
}
66
}
67
 
67
 
68
SEXP do_devcopy(SEXP call, SEXP op, SEXP args, SEXP env)
68
SEXP do_devcopy(SEXP call, SEXP op, SEXP args, SEXP env)
69
{
69
{
70
    checkArity_length;
70
    checkArity_length;
71
    GEcopyDisplayList(INTEGER(CAR(args))[0] - 1);
71
    GEcopyDisplayList(INTEGER(CAR(args))[0] - 1);
72
    return R_NilValue;
72
    return R_NilValue;
73
}
73
}
74
 
74
 
75
SEXP do_devcur(SEXP call, SEXP op, SEXP args, SEXP env)
75
SEXP do_devcur(SEXP call, SEXP op, SEXP args, SEXP env)
76
{
76
{
77
    SEXP cd = allocVector(INTSXP, 1);
77
    SEXP cd = allocVector(INTSXP, 1);
78
    checkArity(op, args);
78
    checkArity(op, args);
79
    INTEGER(cd)[0] = curDevice() + 1;
79
    INTEGER(cd)[0] = curDevice() + 1;
80
    return cd;
80
    return cd;
81
}
81
}
82
 
82
 
83
SEXP do_devnext(SEXP call, SEXP op, SEXP args, SEXP env)
83
SEXP do_devnext(SEXP call, SEXP op, SEXP args, SEXP env)
84
{
84
{
85
    SEXP nd = allocVector(INTSXP, 1);
85
    SEXP nd = allocVector(INTSXP, 1);
86
    checkArity_length;
86
    checkArity_length;
87
    INTEGER(nd)[0] = nextDevice(INTEGER(CAR(args))[0] - 1) + 1;
87
    INTEGER(nd)[0] = nextDevice(INTEGER(CAR(args))[0] - 1) + 1;
88
    return nd;
88
    return nd;
89
}
89
}
90
 
90
 
91
SEXP do_devprev(SEXP call, SEXP op, SEXP args, SEXP env)
91
SEXP do_devprev(SEXP call, SEXP op, SEXP args, SEXP env)
92
{
92
{
93
    SEXP pd = allocVector(INTSXP, 1);
93
    SEXP pd = allocVector(INTSXP, 1);
94
    checkArity_length;
94
    checkArity_length;
95
    INTEGER(pd)[0] = prevDevice(INTEGER(CAR(args))[0] - 1) + 1;
95
    INTEGER(pd)[0] = prevDevice(INTEGER(CAR(args))[0] - 1) + 1;
96
    return pd;
96
    return pd;
97
}
97
}
98
 
98
 
99
SEXP do_devset(SEXP call, SEXP op, SEXP args, SEXP env)
99
SEXP do_devset(SEXP call, SEXP op, SEXP args, SEXP env)
100
{
100
{
101
    int devNum = INTEGER(CAR(args))[0] - 1;
101
    int devNum = INTEGER(CAR(args))[0] - 1;
102
    SEXP sd = allocVector(INTSXP, 1);
102
    SEXP sd = allocVector(INTSXP, 1);
103
    checkArity(op, args);
103
    checkArity(op, args);
104
    INTEGER(sd)[0] = selectDevice(devNum) + 1;
104
    INTEGER(sd)[0] = selectDevice(devNum) + 1;
105
    return sd;
105
    return sd;
106
}
106
}
107
 
107
 
108
SEXP do_devoff(SEXP call, SEXP op, SEXP args, SEXP env)
108
SEXP do_devoff(SEXP call, SEXP op, SEXP args, SEXP env)
109
{
109
{
110
    checkArity_length;
110
    checkArity_length;
111
    killDevice(INTEGER(CAR(args))[0] - 1);
111
    killDevice(INTEGER(CAR(args))[0] - 1);
112
    return R_NilValue;
112
    return R_NilValue;
113
}
113
}
114
 
114
 
115
 
115
 
116
/*  P A R A M E T E R	 U T I L I T I E S  */
116
/*  P A R A M E T E R	 U T I L I T I E S  */
117
 
117
 
118
 
118
 
119
/* ProcessInLinePars handles inline par specifications in graphics functions.
119
/* ProcessInLinePars handles inline par specifications in graphics functions.
120
 * It does this by calling Specify2() from ./par.c */
120
 * It does this by calling Specify2() from ./par.c */
121
 
121
 
122
void ProcessInlinePars(SEXP s, DevDesc *dd, SEXP call)
122
void ProcessInlinePars(SEXP s, DevDesc *dd, SEXP call)
123
{
123
{
124
    if (isList(s)) {
124
    if (isList(s)) {
125
	while (s != R_NilValue) {
125
	while (s != R_NilValue) {
126
	    if (isList(CAR(s)))
126
	    if (isList(CAR(s)))
127
		ProcessInlinePars(CAR(s), dd, call);
127
		ProcessInlinePars(CAR(s), dd, call);
128
	    else if (TAG(s) != R_NilValue)
128
	    else if (TAG(s) != R_NilValue)
129
	    Specify2(CHAR(PRINTNAME(TAG(s))), CAR(s), dd, call);
129
	    Specify2(CHAR(PRINTNAME(TAG(s))), CAR(s), dd, call);
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
 
140
    n = length(pch);
165
    n = length(pch);
141
    if (n == 0) {
166
    if (n == 0) {
142
	ans = allocVector(INTSXP, 1);
167
	ans = allocVector(INTSXP, 1);
143
	INTEGER(ans)[0] = dflt;
168
	INTEGER(ans)[0] = dflt;
144
    }
169
    }
145
    else if (isList(pch)) {
170
    else if (isList(pch)) {
146
	ans = allocVector(INTSXP, n);
171
	ans = allocVector(INTSXP, n);
147
	for (i = 0; pch != R_NilValue;	pch = CDR(pch))
172
	for (i = 0; pch != R_NilValue;	pch = CDR(pch))
148
	    INTEGER(ans)[i++] = asInteger(CAR(pch));
173
	    INTEGER(ans)[i++] = asInteger(CAR(pch));
149
    }
174
    }
150
    else if (isInteger(pch)) {
175
    else if (isInteger(pch)) {
151
	ans = allocVector(INTSXP, n);
176
	ans = allocVector(INTSXP, n);
152
	for (i = 0; i < n; i++)
177
	for (i = 0; i < n; i++)
153
	    INTEGER(ans)[i] = INTEGER(pch)[i];
178
	    INTEGER(ans)[i] = INTEGER(pch)[i];
154
    }
179
    }
155
    else if (isReal(pch)) {
180
    else if (isReal(pch)) {
156
	ans = allocVector(INTSXP, n);
181
	ans = allocVector(INTSXP, n);
157
	for (i = 0; i < n; i++)
182
	for (i = 0; i < n; i++)
158
	    INTEGER(ans)[i] = R_FINITE(REAL(pch)[i]) ?
183
	    INTEGER(ans)[i] = R_FINITE(REAL(pch)[i]) ?
159
		REAL(pch)[i] : NA_INTEGER;
184
		REAL(pch)[i] : NA_INTEGER;
160
    }
185
    }
161
    else if (isString(pch)) {
186
    else if (isString(pch)) {
162
	ans = allocVector(INTSXP, n);
187
	ans = allocVector(INTSXP, n);
163
	for (i = 0; i < n; i++)
188
	for (i = 0; i < n; i++)
164
	    INTEGER(ans)[i] = STRING_ELT(pch, i) != NA_STRING ?
189
	    INTEGER(ans)[i] = STRING_ELT(pch, i) != NA_STRING ?
165
		CHAR(STRING_ELT(pch, i))[0] : NA_INTEGER;
190
		CHAR(STRING_ELT(pch, i))[0] : NA_INTEGER;
166
    }
191
    }
167
    else if (isLogical(pch)) {/* NA, but not TRUE/FALSE */
192
    else if (isLogical(pch)) {/* NA, but not TRUE/FALSE */
168
	ans = allocVector(INTSXP, n);
193
	ans = allocVector(INTSXP, n);
169
	for (i = 0; i < n; i++)
194
	for (i = 0; i < n; i++)
170
	    if(LOGICAL(pch)[i] == NA_LOGICAL)
195
	    if(LOGICAL(pch)[i] == NA_LOGICAL)
171
		INTEGER(ans)[i] = NA_INTEGER;
196
		INTEGER(ans)[i] = NA_INTEGER;
172
	    else error("only NA allowed in logical plotting symbol");
197
	    else error("only NA allowed in logical plotting symbol");
173
    }
198
    }
174
    else error("invalid plotting symbol");
199
    else error("invalid plotting symbol");
175
    for (i = 0; i < n; i++) {
200
    for (i = 0; i < n; i++) {
176
	if (INTEGER(ans)[i] < 0 && INTEGER(ans)[i] != NA_INTEGER)
201
	if (INTEGER(ans)[i] < 0 && INTEGER(ans)[i] != NA_INTEGER)
177
	    INTEGER(ans)[i] = dflt;
202
	    INTEGER(ans)[i] = dflt;
178
    }
203
    }
179
    return ans;
204
    return ans;
180
}
205
}
181
 
206
 
182
SEXP FixupLty(SEXP lty, int dflt)
207
SEXP FixupLty(SEXP lty, int dflt)
183
{
208
{
184
    int i, n;
209
    int i, n;
185
    SEXP ans;
210
    SEXP ans;
186
    n = length(lty);
211
    n = length(lty);
187
    if (n == 0) {
212
    if (n == 0) {
188
	ans = allocVector(INTSXP, 1);
213
	ans = allocVector(INTSXP, 1);
189
	INTEGER(ans)[0] = dflt;
214
	INTEGER(ans)[0] = dflt;
190
    }
215
    }
191
    else {
216
    else {
192
	ans = allocVector(INTSXP, n);
217
	ans = allocVector(INTSXP, n);
193
	for (i = 0; i < n; i++)
218
	for (i = 0; i < n; i++)
194
	    INTEGER(ans)[i] = LTYpar(lty, i);
219
	    INTEGER(ans)[i] = LTYpar(lty, i);
195
    }
220
    }
196
    return ans;
221
    return ans;
197
}
222
}
198
 
223
 
199
SEXP FixupLwd(SEXP lwd, double dflt)
224
SEXP FixupLwd(SEXP lwd, double dflt)
200
{
225
{
201
    int i, n;
226
    int i, n;
202
    double w;
227
    double w;
203
    SEXP ans = NULL;
228
    SEXP ans = NULL;
204
 
229
 
205
    n = length(lwd);
230
    n = length(lwd);
206
    if (n == 0) {
231
    if (n == 0) {
207
	ans = allocVector(REALSXP, 1);
232
	ans = allocVector(REALSXP, 1);
208
	REAL(ans)[0] = dflt;
233
	REAL(ans)[0] = dflt;
209
    }
234
    }
210
    else {
235
    else {
211
	PROTECT(lwd = coerceVector(lwd, REALSXP));
236
	PROTECT(lwd = coerceVector(lwd, REALSXP));
212
	n = length(lwd);
237
	n = length(lwd);
213
	ans = allocVector(REALSXP, n);
238
	ans = allocVector(REALSXP, n);
214
	for (i = 0; i < n; i++) {
239
	for (i = 0; i < n; i++) {
215
	    w = REAL(lwd)[i];
240
	    w = REAL(lwd)[i];
216
	    if (w < 0) w = NA_REAL;
241
	    if (w < 0) w = NA_REAL;
217
	    REAL(ans)[i] = w;
242
	    REAL(ans)[i] = w;
218
 
243
 
219
	}
244
	}
220
	UNPROTECT(1);
245
	UNPROTECT(1);
221
    }
246
    }
222
    return ans;
247
    return ans;
223
}
248
}
224
 
249
 
225
SEXP FixupFont(SEXP font, int dflt)
250
SEXP FixupFont(SEXP font, int dflt)
226
{
251
{
227
    int i, k, n;
252
    int i, k, n;
228
    SEXP ans = R_NilValue;/* -Wall*/
253
    SEXP ans = R_NilValue;/* -Wall*/
229
    n = length(font);
254
    n = length(font);
230
    if (n == 0) {
255
    if (n == 0) {
231
	ans = allocVector(INTSXP, 1);
256
	ans = allocVector(INTSXP, 1);
232
	INTEGER(ans)[0] = dflt;
257
	INTEGER(ans)[0] = dflt;
233
    }
258
    }
234
    else if (isInteger(font) || isLogical(font)) {
259
    else if (isInteger(font) || isLogical(font)) {
235
	ans = allocVector(INTSXP, n);
260
	ans = allocVector(INTSXP, n);
236
	for (i = 0; i < n; i++) {
261
	for (i = 0; i < n; i++) {
237
	    k = INTEGER(font)[i];
262
	    k = INTEGER(font)[i];
238
#ifndef Win32
263
#ifndef Win32
239
	    if (k < 1 || k > 4) k = NA_INTEGER;
264
	    if (k < 1 || k > 4) k = NA_INTEGER;
240
#else
265
#else
241
	    if (k < 1 || k > 32) k = NA_INTEGER;
266
	    if (k < 1 || k > 32) k = NA_INTEGER;
242
#endif
267
#endif
243
	    INTEGER(ans)[i] = k;
268
	    INTEGER(ans)[i] = k;
244
	}
269
	}
245
    }
270
    }
246
    else if (isReal(font)) {
271
    else if (isReal(font)) {
247
	ans = allocVector(INTSXP, n);
272
	ans = allocVector(INTSXP, n);
248
	for (i = 0; i < n; i++) {
273
	for (i = 0; i < n; i++) {
249
	    k = REAL(font)[i];
274
	    k = REAL(font)[i];
250
#ifndef Win32
275
#ifndef Win32
251
	    if (k < 1 || k > 4) k = NA_INTEGER;
276
	    if (k < 1 || k > 4) k = NA_INTEGER;
252
#else
277
#else
253
	    if (k < 1 || k > 32) k = NA_INTEGER;
278
	    if (k < 1 || k > 32) k = NA_INTEGER;
254
#endif
279
#endif
255
	    INTEGER(ans)[i] = k;
280
	    INTEGER(ans)[i] = k;
256
	}
281
	}
257
    }
282
    }
258
    else error("invalid font specification");
283
    else error("invalid font specification");
259
    return ans;
284
    return ans;
260
}
285
}
261
 
286
 
262
SEXP FixupCol(SEXP col, unsigned int dflt)
287
SEXP FixupCol(SEXP col, unsigned int dflt)
263
{
288
{
264
    int i, n;
289
    int i, n;
265
    SEXP ans;
290
    SEXP ans;
266
    n = length(col);
291
    n = length(col);
267
    if (n == 0) {
292
    if (n == 0) {
268
	ans = allocVector(INTSXP, 1);
293
	ans = allocVector(INTSXP, 1);
269
	INTEGER(ans)[0] = dflt;
294
	INTEGER(ans)[0] = dflt;
270
    }
295
    }
271
    else {
296
    else {
272
	ans = allocVector(INTSXP, n);
297
	ans = allocVector(INTSXP, n);
273
	if (isList(col))
298
	if (isList(col))
274
	    for (i = 0; i < n; i++) {
299
	    for (i = 0; i < n; i++) {
275
		INTEGER(ans)[i] = RGBpar(CAR(col), 0);
300
		INTEGER(ans)[i] = RGBpar(CAR(col), 0);
276
		col = CDR(col);
301
		col = CDR(col);
277
	    }
302
	    }
278
	else
303
	else
279
	    for (i = 0; i < n; i++)
304
	    for (i = 0; i < n; i++)
280
		INTEGER(ans)[i] = RGBpar(col, i);
305
		INTEGER(ans)[i] = RGBpar(col, i);
281
    }
306
    }
282
    return ans;
307
    return ans;
283
}
308
}
284
 
309
 
285
SEXP FixupCex(SEXP cex, double dflt)
310
SEXP FixupCex(SEXP cex, double dflt)
286
{
311
{
287
    SEXP ans;
312
    SEXP ans;
288
    int i, n;
313
    int i, n;
289
    n = length(cex);
314
    n = length(cex);
290
    if (n == 0) {
315
    if (n == 0) {
291
	ans = allocVector(REALSXP, 1);
316
	ans = allocVector(REALSXP, 1);
292
	if (R_FINITE(dflt) && dflt > 0)
317
	if (R_FINITE(dflt) && dflt > 0)
293
	    REAL(ans)[0] = dflt;
318
	    REAL(ans)[0] = dflt;
294
	else
319
	else
295
	    REAL(ans)[0] = NA_REAL;
320
	    REAL(ans)[0] = NA_REAL;
296
    }
321
    }
297
    else {
322
    else {
298
	double c;
323
	double c;
299
	ans = allocVector(REALSXP, n);
324
	ans = allocVector(REALSXP, n);
300
	if (isReal(cex))
325
	if (isReal(cex))
301
	    for (i = 0; i < n; i++) {
326
	    for (i = 0; i < n; i++) {
302
		c = REAL(cex)[i];
327
		c = REAL(cex)[i];
303
		if (R_FINITE(c) && c > 0)
328
		if (R_FINITE(c) && c > 0)
304
		    REAL(ans)[i] = c;
329
		    REAL(ans)[i] = c;
305
		else
330
		else
306
		    REAL(ans)[i] = NA_REAL;
331
		    REAL(ans)[i] = NA_REAL;
307
	    }
332
	    }
308
	else if (isInteger(cex) || isLogical(cex))
333
	else if (isInteger(cex) || isLogical(cex))
309
 
334
 
310
	    for (i = 0; i < n; i++) {
335
	    for (i = 0; i < n; i++) {
311
		c = INTEGER(cex)[i];
336
		c = INTEGER(cex)[i];
312
		if (c == NA_INTEGER || c <= 0)
337
		if (c == NA_INTEGER || c <= 0)
313
		    c = NA_REAL;
338
		    c = NA_REAL;
314
		REAL(ans)[i] = c;
339
		REAL(ans)[i] = c;
315
	    }
340
	    }
316
    }
341
    }
317
    return ans;
342
    return ans;
318
}
343
}
319
 
344
 
320
SEXP FixupVFont(SEXP vfont) {
345
SEXP FixupVFont(SEXP vfont) {
321
    SEXP ans = R_NilValue;
346
    SEXP ans = R_NilValue;
322
    if (!isNull(vfont)) {
347
    if (!isNull(vfont)) {
323
	SEXP vf;
348
	SEXP vf;
324
	int typeface, fontindex;
349
	int typeface, fontindex;
325
	int minindex, maxindex=0;/* -Wall*/
350
	int minindex, maxindex=0;/* -Wall*/
326
	int i;
351
	int i;
327
	PROTECT(vf = coerceVector(vfont, INTSXP));
352
	PROTECT(vf = coerceVector(vfont, INTSXP));
328
	if (length(vf) != 2)
353
	if (length(vf) != 2)
329
	    error("Invalid vfont value");
354
	    error("Invalid vfont value");
330
	typeface = INTEGER(vf)[0];
355
	typeface = INTEGER(vf)[0];
331
	if (typeface < 0 || typeface > 7)
356
	if (typeface < 0 || typeface > 7)
332
	    error("Invalid vfont value [typeface]");
357
	    error("Invalid vfont value [typeface]");
333
	/* For each of the typefaces {0..7}, there are several fontindices
358
	/* For each of the typefaces {0..7}, there are several fontindices
334
	   available; how many depends on the typeface.
359
	   available; how many depends on the typeface.
335
	   The possible combinations are "given" in ./g_fontdb.c
360
	   The possible combinations are "given" in ./g_fontdb.c
336
	   and also listed in help(Hershey).
361
	   and also listed in help(Hershey).
337
	 */
362
	 */
338
	minindex = 1;
363
	minindex = 1;
339
	switch (typeface) {
364
	switch (typeface) {
340
	case 0: /* serif */
365
	case 0: /* serif */
341
	    maxindex = 7;	    break;
366
	    maxindex = 7;	    break;
342
	case 1: /* sans serif */
367
	case 1: /* sans serif */
343
	case 6: /* serif symbol */
368
	case 6: /* serif symbol */
344
	    maxindex = 4;	    break;
369
	    maxindex = 4;	    break;
345
	case 2: /* script */
370
	case 2: /* script */
346
	    maxindex = 3;	    break;
371
	    maxindex = 3;	    break;
347
	case 3: /* gothic english */
372
	case 3: /* gothic english */
348
	case 4: /* gothic german */
373
	case 4: /* gothic german */
349
	case 5: /* gothic italian */
374
	case 5: /* gothic italian */
350
	    maxindex = 1;	    break;
375
	    maxindex = 1;	    break;
351
	case 7: /* sans serif symbol */
376
	case 7: /* sans serif symbol */
352
	    maxindex = 2;
377
	    maxindex = 2;
353
	}
378
	}
354
	fontindex = INTEGER(vf)[1];
379
	fontindex = INTEGER(vf)[1];
355
	if (fontindex < minindex || fontindex > maxindex)
380
	if (fontindex < minindex || fontindex > maxindex)
356
	    error("Invalid vfont value [fontindex]");
381
	    error("Invalid vfont value [fontindex]");
357
	ans = allocVector(INTSXP, 2);
382
	ans = allocVector(INTSXP, 2);
358
	for (i=0; i<2; i++)
383
	for (i=0; i<2; i++)
359
	    INTEGER(ans)[i] = INTEGER(vf)[i];
384
	    INTEGER(ans)[i] = INTEGER(vf)[i];
360
	UNPROTECT(1);
385
	UNPROTECT(1);
361
    }
386
    }
362
    return ans;
387
    return ans;
363
}
388
}
364
 
389
 
365
/* GetTextArg() : extract from call and possibly set text arguments
390
/* GetTextArg() : extract from call and possibly set text arguments
366
 *  ("label", col=, cex=, font=, vfont=)
391
 *  ("label", col=, cex=, font=, vfont=)
367
 *
392
 *
368
 * Main purpose: Treat things like  title(main = list("This Title", font= 4))
393
 * Main purpose: Treat things like  title(main = list("This Title", font= 4))
369
 *
394
 *
370
 * Called from	do_title()  [only, currently]
395
 * Called from	do_title()  [only, currently]
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:
389
    case SYMSXP:
415
    case SYMSXP:
390
	UNPROTECT(1);
416
	UNPROTECT(1);
391
	PROTECT(txt = coerceVector(spec, EXPRSXP));
417
	PROTECT(txt = coerceVector(spec, EXPRSXP));
392
	break;
418
	break;
393
    case VECSXP:
419
    case VECSXP:
394
	if (length(spec) == 0) {
420
	if (length(spec) == 0) {
395
	    *ptxt = R_NilValue;
421
	    *ptxt = R_NilValue;
396
	}
422
	}
397
	else {
423
	else {
398
	    nms = getAttrib(spec, R_NamesSymbol);
424
	    nms = getAttrib(spec, R_NamesSymbol);
399
	    if (nms==R_NilValue){ /* PR#1939 */
425
	    if (nms==R_NilValue){ /* PR#1939 */
400
	       txt = VECTOR_ELT(spec, 0);
426
	       txt = VECTOR_ELT(spec, 0);
401
	       if (TYPEOF(txt) == LANGSXP ||TYPEOF(txt) == SYMSXP ) {
427
	       if (TYPEOF(txt) == LANGSXP ||TYPEOF(txt) == SYMSXP ) {
402
		    UNPROTECT(1);
428
		    UNPROTECT(1);
403
		    PROTECT(txt = coerceVector(txt, EXPRSXP));
429
		    PROTECT(txt = coerceVector(txt, EXPRSXP));
404
	       }
430
	       }
405
	       else if (!isExpression(txt)) {
431
	       else if (!isExpression(txt)) {
406
		    UNPROTECT(1);
432
		    UNPROTECT(1);
407
		    PROTECT(txt = coerceVector(txt, STRSXP));
433
		    PROTECT(txt = coerceVector(txt, STRSXP));
408
	       }
434
	       }
409
	    } else {
435
	    } else {
410
	       n = length(nms);
436
	       n = length(nms);
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")) {
422
		    vfont = FixupVFont(VECTOR_ELT(spec, i));
452
		    vfont = FixupVFont(VECTOR_ELT(spec, i));
423
		}
453
		}
424
		else if (!strcmp(CHAR(STRING_ELT(nms, i)), "")) {
454
		else if (!strcmp(CHAR(STRING_ELT(nms, i)), "")) {
425
		    txt = VECTOR_ELT(spec, i);
455
		    txt = VECTOR_ELT(spec, i);
426
		    if (TYPEOF(txt) == LANGSXP || TYPEOF(txt)==SYMSXP) {
456
		    if (TYPEOF(txt) == LANGSXP || TYPEOF(txt)==SYMSXP) {
427
			UNPROTECT(1);
457
			UNPROTECT(1);
428
			PROTECT(txt = coerceVector(txt, EXPRSXP));
458
			PROTECT(txt = coerceVector(txt, EXPRSXP));
429
		    }
459
		    }
430
		    else if (!isExpression(txt)) {
460
		    else if (!isExpression(txt)) {
431
			UNPROTECT(1);
461
			UNPROTECT(1);
432
			PROTECT(txt = coerceVector(txt, STRSXP));
462
			PROTECT(txt = coerceVector(txt, STRSXP));
433
		    }
463
		    }
434
		}
464
		}
435
		else errorcall(call, "invalid graphics parameter");
465
		else errorcall(call, "invalid graphics parameter");
436
	       }
466
	       }
437
	    }
467
	    }
438
	}
468
	}
439
	break;
469
	break;
440
    case STRSXP:
470
    case STRSXP:
441
    case EXPRSXP:
471
    case EXPRSXP:
442
	txt = spec;
472
	txt = spec;
443
	break;
473
	break;
444
    default:
474
    default:
445
	txt = coerceVector(spec, STRSXP);
475
	txt = coerceVector(spec, STRSXP);
446
	break;
476
	break;
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
 
458
 
488
 
459
    /* GRAPHICS FUNCTION ENTRY POINTS */
489
    /* GRAPHICS FUNCTION ENTRY POINTS */
460
 
490
 
461
 
491
 
462
SEXP do_plot_new(SEXP call, SEXP op, SEXP args, SEXP env)
492
SEXP do_plot_new(SEXP call, SEXP op, SEXP args, SEXP env)
463
{
493
{
464
    /* plot.new() - create a new plot "frame" */
494
    /* plot.new() - create a new plot "frame" */
465
 
495
 
466
    DevDesc *dd;
496
    DevDesc *dd;
467
 
497
 
468
    checkArity(op, args);
498
    checkArity(op, args);
469
 
499
 
470
    dd = GNewPlot(GRecording(call));
500
    dd = GNewPlot(GRecording(call));
471
 
501
 
472
    Rf_dpptr(dd)->xlog = Rf_gpptr(dd)->xlog = FALSE;
502
    Rf_dpptr(dd)->xlog = Rf_gpptr(dd)->xlog = FALSE;
473
    Rf_dpptr(dd)->ylog = Rf_gpptr(dd)->ylog = FALSE;
503
    Rf_dpptr(dd)->ylog = Rf_gpptr(dd)->ylog = FALSE;
474
 
504
 
475
    GScale(0.0, 1.0, 1, dd);
505
    GScale(0.0, 1.0, 1, dd);
476
    GScale(0.0, 1.0, 2, dd);
506
    GScale(0.0, 1.0, 2, dd);
477
    GMapWin2Fig(dd);
507
    GMapWin2Fig(dd);
478
    GSetState(1, dd);
508
    GSetState(1, dd);
479
 
509
 
480
    if (GRecording(call))
510
    if (GRecording(call))
481
	recordGraphicOperation(op, args, dd);
511
	recordGraphicOperation(op, args, dd);
482
    return R_NilValue;
512
    return R_NilValue;
483
}
513
}
484
 
514
 
485
 
515
 
486
/*
516
/*
487
 *  SYNOPSIS
517
 *  SYNOPSIS
488
 *
518
 *
489
 *	plot.window(xlim, ylim, log="", asp=NA)
519
 *	plot.window(xlim, ylim, log="", asp=NA)
490
 *
520
 *
491
 *  DESCRIPTION
521
 *  DESCRIPTION
492
 *
522
 *
493
 *	This function sets up the world coordinates for a graphics
523
 *	This function sets up the world coordinates for a graphics
494
 *	window.	 Note that if asp is a finite positive value then
524
 *	window.	 Note that if asp is a finite positive value then
495
 *	the window is set up so that one data unit in the y direction
525
 *	the window is set up so that one data unit in the y direction
496
 *	is equal in length to one data unit in the x direction divided
526
 *	is equal in length to one data unit in the x direction divided
497
 *	by asp.
527
 *	by asp.
498
 *
528
 *
499
 *	The special case asp == 1 produces plots where distances
529
 *	The special case asp == 1 produces plots where distances
500
 *	between points are represented accurately on screen.
530
 *	between points are represented accurately on screen.
501
 *
531
 *
502
 *  NOTE
532
 *  NOTE
503
 *
533
 *
504
 *	The use of asp can have weird effects when axis is an
534
 *	The use of asp can have weird effects when axis is an
505
 *	interpreted function.  It has to be internal so that the
535
 *	interpreted function.  It has to be internal so that the
506
 *	full computation is captured in the display list.
536
 *	full computation is captured in the display list.
507
 */
537
 */
508
 
538
 
509
SEXP do_plot_window(SEXP call, SEXP op, SEXP args, SEXP env)
539
SEXP do_plot_window(SEXP call, SEXP op, SEXP args, SEXP env)
510
{
540
{
511
    SEXP xlim, ylim, logarg;
541
    SEXP xlim, ylim, logarg;
512
    double asp, xmin, xmax, ymin, ymax;
542
    double asp, xmin, xmax, ymin, ymax;
513
    Rboolean logscale;
543
    Rboolean logscale;
514
    char *p;
544
    char *p;
515
    SEXP originalArgs = args;
545
    SEXP originalArgs = args;
516
    DevDesc *dd = CurrentDevice();
546
    DevDesc *dd = CurrentDevice();
517
 
547
 
518
    if (length(args) < 3)
548
    if (length(args) < 3)
519
	errorcall(call, "at least 3 arguments required");
549
	errorcall(call, "at least 3 arguments required");
520
 
550
 
521
    xlim = CAR(args);
551
    xlim = CAR(args);
522
    if (!isNumeric(xlim) || LENGTH(xlim) != 2)
552
    if (!isNumeric(xlim) || LENGTH(xlim) != 2)
523
	errorcall(call, "invalid xlim");
553
	errorcall(call, "invalid xlim");
524
    args = CDR(args);
554
    args = CDR(args);
525
 
555
 
526
    ylim = CAR(args);
556
    ylim = CAR(args);
527
    if (!isNumeric(ylim) || LENGTH(ylim) != 2)
557
    if (!isNumeric(ylim) || LENGTH(ylim) != 2)
528
	errorcall(call, "invalid ylim");
558
	errorcall(call, "invalid ylim");
529
    args = CDR(args);
559
    args = CDR(args);
530
 
560
 
531
    logscale = FALSE;
561
    logscale = FALSE;
532
    logarg = CAR(args);
562
    logarg = CAR(args);
533
    if (!isString(logarg))
563
    if (!isString(logarg))
534
	errorcall(call, "\"log=\" specification must be character");
564
	errorcall(call, "\"log=\" specification must be character");
535
    p = CHAR(STRING_ELT(logarg, 0));
565
    p = CHAR(STRING_ELT(logarg, 0));
536
    while (*p) {
566
    while (*p) {
537
	switch (*p) {
567
	switch (*p) {
538
	case 'x':
568
	case 'x':
539
	    Rf_dpptr(dd)->xlog = Rf_gpptr(dd)->xlog = logscale = TRUE;
569
	    Rf_dpptr(dd)->xlog = Rf_gpptr(dd)->xlog = logscale = TRUE;
540
	    break;
570
	    break;
541
	case 'y':
571
	case 'y':
542
	    Rf_dpptr(dd)->ylog = Rf_gpptr(dd)->ylog = logscale = TRUE;
572
	    Rf_dpptr(dd)->ylog = Rf_gpptr(dd)->ylog = logscale = TRUE;
543
	    break;
573
	    break;
544
	default:
574
	default:
545
	    errorcall(call,"invalid \"log=%s\" specification",p);
575
	    errorcall(call,"invalid \"log=%s\" specification",p);
546
	}
576
	}
547
	p++;
577
	p++;
548
    }
578
    }
549
    args = CDR(args);
579
    args = CDR(args);
550
 
580
 
551
    asp = (logscale) ? NA_REAL : asReal(CAR(args));;
581
    asp = (logscale) ? NA_REAL : asReal(CAR(args));;
552
    args = CDR(args);
582
    args = CDR(args);
553
 
583
 
554
    GSavePars(dd);
584
    GSavePars(dd);
555
    ProcessInlinePars(args, dd, call);
585
    ProcessInlinePars(args, dd, call);
556
 
586
 
557
    if (isInteger(xlim)) {
587
    if (isInteger(xlim)) {
558
	if (INTEGER(xlim)[0] == NA_INTEGER || INTEGER(xlim)[1] == NA_INTEGER)
588
	if (INTEGER(xlim)[0] == NA_INTEGER || INTEGER(xlim)[1] == NA_INTEGER)
559
	    errorcall(call, "NAs not allowed in xlim");
589
	    errorcall(call, "NAs not allowed in xlim");
560
	xmin = INTEGER(xlim)[0];
590
	xmin = INTEGER(xlim)[0];
561
	xmax = INTEGER(xlim)[1];
591
	xmax = INTEGER(xlim)[1];
562
    }
592
    }
563
    else {
593
    else {
564
	if (!R_FINITE(REAL(xlim)[0]) || !R_FINITE(REAL(xlim)[1]))
594
	if (!R_FINITE(REAL(xlim)[0]) || !R_FINITE(REAL(xlim)[1]))
565
	    errorcall(call, "need finite xlim values");
595
	    errorcall(call, "need finite xlim values");
566
	xmin = REAL(xlim)[0];
596
	xmin = REAL(xlim)[0];
567
	xmax = REAL(xlim)[1];
597
	xmax = REAL(xlim)[1];
568
    }
598
    }
569
    if (isInteger(ylim)) {
599
    if (isInteger(ylim)) {
570
	if (INTEGER(ylim)[0] == NA_INTEGER || INTEGER(ylim)[1] == NA_INTEGER)
600
	if (INTEGER(ylim)[0] == NA_INTEGER || INTEGER(ylim)[1] == NA_INTEGER)
571
	    errorcall(call, "NAs not allowed in ylim");
601
	    errorcall(call, "NAs not allowed in ylim");
572
	ymin = INTEGER(ylim)[0];
602
	ymin = INTEGER(ylim)[0];
573
	ymax = INTEGER(ylim)[1];
603
	ymax = INTEGER(ylim)[1];
574
    }
604
    }
575
    else {
605
    else {
576
	if (!R_FINITE(REAL(ylim)[0]) || !R_FINITE(REAL(ylim)[1]))
606
	if (!R_FINITE(REAL(ylim)[0]) || !R_FINITE(REAL(ylim)[1]))
577
	    errorcall(call, "need finite ylim values");
607
	    errorcall(call, "need finite ylim values");
578
	ymin = REAL(ylim)[0];
608
	ymin = REAL(ylim)[0];
579
	ymax = REAL(ylim)[1];
609
	ymax = REAL(ylim)[1];
580
    }
610
    }
581
    if ((Rf_dpptr(dd)->xlog && (xmin < 0 || xmax < 0)) ||
611
    if ((Rf_dpptr(dd)->xlog && (xmin < 0 || xmax < 0)) ||
582
       (Rf_dpptr(dd)->ylog && (ymin < 0 || ymax < 0)))
612
       (Rf_dpptr(dd)->ylog && (ymin < 0 || ymax < 0)))
583
	    errorcall(call, "Logarithmic axis must have positive limits");
613
	    errorcall(call, "Logarithmic axis must have positive limits");
584
 
614
 
585
    if (R_FINITE(asp) && asp > 0) {
615
    if (R_FINITE(asp) && asp > 0) {
586
	double pin1, pin2, scale, xdelta, ydelta, xscale, yscale, xadd, yadd;
616
	double pin1, pin2, scale, xdelta, ydelta, xscale, yscale, xadd, yadd;
587
	pin1 = GConvertXUnits(1.0, NPC, INCHES, dd);
617
	pin1 = GConvertXUnits(1.0, NPC, INCHES, dd);
588
	pin2 = GConvertYUnits(1.0, NPC, INCHES, dd);
618
	pin2 = GConvertYUnits(1.0, NPC, INCHES, dd);
589
	xdelta = fabs(xmax - xmin) / asp;
619
	xdelta = fabs(xmax - xmin) / asp;
590
	ydelta = fabs(ymax - ymin);
620
	ydelta = fabs(ymax - ymin);
591
	if(xdelta == 0.0 && ydelta == 0.0) {
621
	if(xdelta == 0.0 && ydelta == 0.0) {
592
	    /* We really do mean zero: small non-zero values work
622
	    /* We really do mean zero: small non-zero values work
593
	       Mimic the behaviour of GScale for the x axis. */
623
	       Mimic the behaviour of GScale for the x axis. */
594
	    xadd = yadd = ((xmin == 0.0) ? 1 : 0.4) * asp;
624
	    xadd = yadd = ((xmin == 0.0) ? 1 : 0.4) * asp;
595
	    xadd *= asp;
625
	    xadd *= asp;
596
	} else {
626
	} else {
597
	    xscale = pin1 / xdelta;
627
	    xscale = pin1 / xdelta;
598
	    yscale = pin2 / ydelta;
628
	    yscale = pin2 / ydelta;
599
	    scale = (xscale < yscale) ? xscale : yscale;
629
	    scale = (xscale < yscale) ? xscale : yscale;
600
	    xadd = .5 * (pin1 / scale - xdelta) * asp;
630
	    xadd = .5 * (pin1 / scale - xdelta) * asp;
601
	    yadd = .5 * (pin2 / scale - ydelta);
631
	    yadd = .5 * (pin2 / scale - ydelta);
602
	}
632
	}
603
	GScale(xmin - xadd, xmax + xadd, 1, dd);
633
	GScale(xmin - xadd, xmax + xadd, 1, dd);
604
	GScale(ymin - yadd, ymax + yadd, 2, dd);
634
	GScale(ymin - yadd, ymax + yadd, 2, dd);
605
    }
635
    }
606
    else {
636
    else {
607
	GScale(xmin, xmax, 1, dd);
637
	GScale(xmin, xmax, 1, dd);
608
	GScale(ymin, ymax, 2, dd);
638
	GScale(ymin, ymax, 2, dd);
609
    }
639
    }
610
    GMapWin2Fig(dd);
640
    GMapWin2Fig(dd);
611
    GRestorePars(dd);
641
    GRestorePars(dd);
612
    /* NOTE: the operation is only recorded if there was no "error" */
642
    /* NOTE: the operation is only recorded if there was no "error" */
613
    if (GRecording(call))
643
    if (GRecording(call))
614
	recordGraphicOperation(op, originalArgs, dd);
644
	recordGraphicOperation(op, originalArgs, dd);
615
    return R_NilValue;
645
    return R_NilValue;
616
}
646
}
617
 
647
 
618
void GetAxisLimits(double left, double right, double *low, double *high)
648
void GetAxisLimits(double left, double right, double *low, double *high)
619
{
649
{
620
/*	Called from do_axis()	such as
650
/*	Called from do_axis()	such as
621
 *	GetAxisLimits(Rf_gpptr(dd)->usr[0], Rf_gpptr(dd)->usr[1], &low, &high)
651
 *	GetAxisLimits(Rf_gpptr(dd)->usr[0], Rf_gpptr(dd)->usr[1], &low, &high)
622
 *
652
 *
623
 *	Computes  *low < left, right < *high  (even if left=right)
653
 *	Computes  *low < left, right < *high  (even if left=right)
624
 */
654
 */
625
    double eps;
655
    double eps;
626
    if (left > right) {/* swap */
656
    if (left > right) {/* swap */
627
	eps = left; left = right; right = eps;
657
	eps = left; left = right; right = eps;
628
    }
658
    }
629
    eps = right - left;
659
    eps = right - left;
630
    if (eps == 0.)
660
    if (eps == 0.)
631
	eps = 0.5 * FLT_EPSILON;
661
	eps = 0.5 * FLT_EPSILON;
632
    else
662
    else
633
	eps *= FLT_EPSILON;
663
	eps *= FLT_EPSILON;
634
    *low = left - eps;
664
    *low = left - eps;
635
    *high = right + eps;
665
    *high = right + eps;
636
}
666
}
637
 
667
 
638
 
668
 
639
/* axis(side, at, labels, ...) */
669
/* axis(side, at, labels, ...) */
640
 
670
 
641
SEXP labelformat(SEXP labels)
671
SEXP labelformat(SEXP labels)
642
{
672
{
643
    /* format(labels): i.e. from numbers to strings */
673
    /* format(labels): i.e. from numbers to strings */
644
    SEXP ans = R_NilValue;/* -Wall*/
674
    SEXP ans = R_NilValue;/* -Wall*/
645
    int i, n, w, d, e, wi, di, ei;
675
    int i, n, w, d, e, wi, di, ei;
646
    char *strp;
676
    char *strp;
647
    n = length(labels);
677
    n = length(labels);
648
    R_print.digits = 7;/* maximally 7 digits -- ``burnt in'';
678
    R_print.digits = 7;/* maximally 7 digits -- ``burnt in'';
649
			  S-PLUS <= 5.x has about 6
679
			  S-PLUS <= 5.x has about 6
650
			  (but really uses single precision..) */
680
			  (but really uses single precision..) */
651
    switch(TYPEOF(labels)) {
681
    switch(TYPEOF(labels)) {
652
    case LGLSXP:
682
    case LGLSXP:
653
	PROTECT(ans = allocVector(STRSXP, n));
683
	PROTECT(ans = allocVector(STRSXP, n));
654
	for (i = 0; i < n; i++) {
684
	for (i = 0; i < n; i++) {
655
	    strp = EncodeLogical(LOGICAL(labels)[i], 0);
685
	    strp = EncodeLogical(LOGICAL(labels)[i], 0);
656
	    SET_STRING_ELT(ans, i, mkChar(strp));
686
	    SET_STRING_ELT(ans, i, mkChar(strp));
657
	}
687
	}
658
	UNPROTECT(1);
688
	UNPROTECT(1);
659
	break;
689
	break;
660
    case INTSXP:
690
    case INTSXP:
661
	PROTECT(ans = allocVector(STRSXP, n));
691
	PROTECT(ans = allocVector(STRSXP, n));
662
	for (i = 0; i < n; i++) {
692
	for (i = 0; i < n; i++) {
663
	    strp = EncodeInteger(INTEGER(labels)[i], 0);
693
	    strp = EncodeInteger(INTEGER(labels)[i], 0);
664
	    SET_STRING_ELT(ans, i, mkChar(strp));
694
	    SET_STRING_ELT(ans, i, mkChar(strp));
665
	}
695
	}
666
	UNPROTECT(1);
696
	UNPROTECT(1);
667
	break;
697
	break;
668
    case REALSXP:
698
    case REALSXP:
669
	formatReal(REAL(labels), n, &w, &d, &e, 0);
699
	formatReal(REAL(labels), n, &w, &d, &e, 0);
670
	PROTECT(ans = allocVector(STRSXP, n));
700
	PROTECT(ans = allocVector(STRSXP, n));
671
	for (i = 0; i < n; i++) {
701
	for (i = 0; i < n; i++) {
672
	    strp = EncodeReal(REAL(labels)[i], 0, d, e);
702
	    strp = EncodeReal(REAL(labels)[i], 0, d, e);
673
	    SET_STRING_ELT(ans, i, mkChar(strp));
703
	    SET_STRING_ELT(ans, i, mkChar(strp));
674
	}
704
	}
675
	UNPROTECT(1);
705
	UNPROTECT(1);
676
	break;
706
	break;
677
    case CPLXSXP:
707
    case CPLXSXP:
678
	formatComplex(COMPLEX(labels), n, &w, &d, &e, &wi, &di, &ei, 0);
708
	formatComplex(COMPLEX(labels), n, &w, &d, &e, &wi, &di, &ei, 0);
679
	PROTECT(ans = allocVector(STRSXP, n));
709
	PROTECT(ans = allocVector(STRSXP, n));
680
	for (i = 0; i < n; i++) {
710
	for (i = 0; i < n; i++) {
681
	    strp = EncodeComplex(COMPLEX(labels)[i], 0, d, e, 0, di, ei);
711
	    strp = EncodeComplex(COMPLEX(labels)[i], 0, d, e, 0, di, ei);
682
	    SET_STRING_ELT(ans, i, mkChar(strp));
712
	    SET_STRING_ELT(ans, i, mkChar(strp));
683
	}
713
	}
684
	UNPROTECT(1);
714
	UNPROTECT(1);
685
	break;
715
	break;
686
    case STRSXP:
716
    case STRSXP:
687
	PROTECT(ans = allocVector(STRSXP, n));
717
	PROTECT(ans = allocVector(STRSXP, n));
688
	for (i = 0; i < n; i++) {
718
	for (i = 0; i < n; i++) {
689
	    SET_STRING_ELT(ans, i, STRING_ELT(labels, i));
719
	    SET_STRING_ELT(ans, i, STRING_ELT(labels, i));
690
	}
720
	}
691
	UNPROTECT(1);
721
	UNPROTECT(1);
692
	break;
722
	break;
693
    default:
723
    default:
694
	error("invalid type for axis labels");
724
	error("invalid type for axis labels");
695
    }
725
    }
696
    return ans;
726
    return ans;
697
}
727
}
698
 
728
 
699
SEXP CreateAtVector(double *axp, double *usr, int nint, Rboolean logflag)
729
SEXP CreateAtVector(double *axp, double *usr, int nint, Rboolean logflag)
700
{
730
{
701
/*	Create an  'at = ...' vector for  axis(.) / do_axis,
731
/*	Create an  'at = ...' vector for  axis(.) / do_axis,
702
 *	i.e., the vector of tick mark locations,
732
 *	i.e., the vector of tick mark locations,
703
 *	when none has been specified (= default).
733
 *	when none has been specified (= default).
704
 *
734
 *
705
 *	axp[0:2] = (x1, x2, nInt), where x1..x2 are the extreme tick marks
735
 *	axp[0:2] = (x1, x2, nInt), where x1..x2 are the extreme tick marks
706
 *                 {unless in log case, where nint \in {1,2,3 ; -1,-2,....}
736
 *                 {unless in log case, where nint \in {1,2,3 ; -1,-2,....}
707
 *                  and the `nint' argument is used.
737
 *                  and the `nint' argument is used.
708
 
738
 
709
 *	The resulting REAL vector must have length >= 1, ideally >= 2
739
 *	The resulting REAL vector must have length >= 1, ideally >= 2
710
 */
740
 */
711
    SEXP at = R_NilValue;/* -Wall*/
741
    SEXP at = R_NilValue;/* -Wall*/
712
    double umin, umax, dn, rng, small;
742
    double umin, umax, dn, rng, small;
713
    int i, n, ne;
743
    int i, n, ne;
714
    if (!logflag || axp[2] < 0) { /* --- linear axis --- Only use axp[] arg. */
744
    if (!logflag || axp[2] < 0) { /* --- linear axis --- Only use axp[] arg. */
715
	n = fabs(axp[2]) + 0.25;/* >= 0 */
745
	n = fabs(axp[2]) + 0.25;/* >= 0 */
716
	dn = imax2(1, n);
746
	dn = imax2(1, n);
717
	rng = axp[1] - axp[0];
747
	rng = axp[1] - axp[0];
718
	small = fabs(rng)/(100.*dn);
748
	small = fabs(rng)/(100.*dn);
719
	at = allocVector(REALSXP, n + 1);
749
	at = allocVector(REALSXP, n + 1);
720
	for (i = 0; i <= n; i++) {
750
	for (i = 0; i <= n; i++) {
721
	    REAL(at)[i] = axp[0] + (i / dn) * rng;
751
	    REAL(at)[i] = axp[0] + (i / dn) * rng;
722
	    if (fabs(REAL(at)[i]) < small)
752
	    if (fabs(REAL(at)[i]) < small)
723
		REAL(at)[i] = 0;
753
		REAL(at)[i] = 0;
724
	}
754
	}
725
    }
755
    }
726
    else { /* ------ log axis ----- */
756
    else { /* ------ log axis ----- */
727
	n = (axp[2] + 0.5);
757
	n = (axp[2] + 0.5);
728
	/* {xy}axp[2] for 'log': GLpretty() [../graphics.c] sets
758
	/* {xy}axp[2] for 'log': GLpretty() [../graphics.c] sets
729
	   n < 0: very small scale ==> linear axis, above, or
759
	   n < 0: very small scale ==> linear axis, above, or
730
	   n = 1,2,3.  see switch() below */
760
	   n = 1,2,3.  see switch() below */
731
	umin = usr[0];
761
	umin = usr[0];
732
	umax = usr[1];
762
	umax = usr[1];
733
	/* Debugging: When does the following happen... ? */
763
	/* Debugging: When does the following happen... ? */
734
	if (umin > umax)
764
	if (umin > umax)
735
	    warning("CreateAtVector \"log\"(from axis()): "
765
	    warning("CreateAtVector \"log\"(from axis()): "
736
		    "usr[0] = %g > %g = usr[1] !", umin, umax);
766
		    "usr[0] = %g > %g = usr[1] !", umin, umax);
737
	dn = axp[0];
767
	dn = axp[0];
738
	if (dn < 1e-300)
768
	if (dn < 1e-300)
739
	    warning("CreateAtVector \"log\"(from axis()): axp[0] = %g !", dn);
769
	    warning("CreateAtVector \"log\"(from axis()): axp[0] = %g !", dn);
740
 
770
 
741
	/* You get the 3 cases below by
771
	/* You get the 3 cases below by
742
	 *  for (y in 1e-5*c(1,2,8))  plot(y, log = "y")
772
	 *  for (y in 1e-5*c(1,2,8))  plot(y, log = "y")
743
	 */
773
	 */
744
	switch(n) {
774
	switch(n) {
745
	case 1: /* large range:	1	 * 10^k */
775
	case 1: /* large range:	1	 * 10^k */
746
	    i = floor(log10(axp[1])) - ceil(log10(axp[0])) + 0.25;
776
	    i = floor(log10(axp[1])) - ceil(log10(axp[0])) + 0.25;
747
	    ne = i / nint + 1;
777
	    ne = i / nint + 1;
748
	    if (ne < 1)
778
	    if (ne < 1)
749
		error("log - axis(), 'at' creation, _LARGE_ range: "
779
		error("log - axis(), 'at' creation, _LARGE_ range: "
750
		      "ne = %d <= 0 !!\n"
780
		      "ne = %d <= 0 !!\n"
751
		      "\t axp[0:1]=(%g,%g) ==> i = %d;	nint = %d",
781
		      "\t axp[0:1]=(%g,%g) ==> i = %d;	nint = %d",
752
		      ne, axp[0],axp[1], i, nint);
782
		      ne, axp[0],axp[1], i, nint);
753
	    rng = pow(10., (double)ne);/* >= 10 */
783
	    rng = pow(10., (double)ne);/* >= 10 */
754
	    n = 0;
784
	    n = 0;
755
	    while (dn < umax) {
785
	    while (dn < umax) {
756
		n++;
786
		n++;
757
		dn *= rng;
787
		dn *= rng;
758
	    }
788
	    }
759
	    if (!n)
789
	    if (!n)
760
		error("log - axis(), 'at' creation, _LARGE_ range: "
790
		error("log - axis(), 'at' creation, _LARGE_ range: "
761
		      "illegal {xy}axp or par; nint=%d\n"
791
		      "illegal {xy}axp or par; nint=%d\n"
762
		      "	 axp[0:1]=(%g,%g), usr[0:1]=(%g,%g); i=%d, ni=%d",
792
		      "	 axp[0:1]=(%g,%g), usr[0:1]=(%g,%g); i=%d, ni=%d",
763
		      nint, axp[0],axp[1], umin,umax, i,ne);
793
		      nint, axp[0],axp[1], umin,umax, i,ne);
764
	    at = allocVector(REALSXP, n);
794
	    at = allocVector(REALSXP, n);
765
	    dn = axp[0];
795
	    dn = axp[0];
766
	    n = 0;
796
	    n = 0;
767
	    while (dn < umax) {
797
	    while (dn < umax) {
768
		REAL(at)[n++] = dn;
798
		REAL(at)[n++] = dn;
769
		dn *= rng;
799
		dn *= rng;
770
	    }
800
	    }
771
	    break;
801
	    break;
772
 
802
 
773
	case 2: /* medium range:  1, 5	  * 10^k */
803
	case 2: /* medium range:  1, 5	  * 10^k */
774
	    n = 0;
804
	    n = 0;
775
	    if (0.5 * dn >= umin) n++;
805
	    if (0.5 * dn >= umin) n++;
776
	    for (;;) {
806
	    for (;;) {
777
		if (dn > umax) break;		n++;
807
		if (dn > umax) break;		n++;
778
		if (5 * dn > umax) break;	n++;
808
		if (5 * dn > umax) break;	n++;
779
		dn *= 10;
809
		dn *= 10;
780
	    }
810
	    }
781
	    if (!n)
811
	    if (!n)
782
		error("log - axis(), 'at' creation, _MEDIUM_ range: "
812
		error("log - axis(), 'at' creation, _MEDIUM_ range: "
783
		      "illegal {xy}axp or par;\n"
813
		      "illegal {xy}axp or par;\n"
784
		      "	 axp[0]= %g, usr[0:1]=(%g,%g)",
814
		      "	 axp[0]= %g, usr[0:1]=(%g,%g)",
785
		      axp[0], umin,umax);
815
		      axp[0], umin,umax);
786
 
816
 
787
	    at = allocVector(REALSXP, n);
817
	    at = allocVector(REALSXP, n);
788
	    dn = axp[0];
818
	    dn = axp[0];
789
	    n = 0;
819
	    n = 0;
790
	    if (0.5 * dn >= umin) REAL(at)[n++] = 0.5 * dn;
820
	    if (0.5 * dn >= umin) REAL(at)[n++] = 0.5 * dn;
791
	    for (;;) {
821
	    for (;;) {
792
		if (dn > umax) break;		REAL(at)[n++] = dn;
822
		if (dn > umax) break;		REAL(at)[n++] = dn;
793
		if (5 * dn > umax) break;	REAL(at)[n++] = 5 * dn;
823
		if (5 * dn > umax) break;	REAL(at)[n++] = 5 * dn;
794
		dn *= 10;
824
		dn *= 10;
795
	    }
825
	    }
796
	    break;
826
	    break;
797
 
827
 
798
	case 3: /* small range:	 1,2,5,10 * 10^k */
828
	case 3: /* small range:	 1,2,5,10 * 10^k */
799
	    n = 0;
829
	    n = 0;
800
	    if (0.2 * dn >= umin) n++;
830
	    if (0.2 * dn >= umin) n++;
801
	    if (0.5 * dn >= umin) n++;
831
	    if (0.5 * dn >= umin) n++;
802
	    for (;;) {
832
	    for (;;) {
803
		if (dn > umax) break;		n++;
833
		if (dn > umax) break;		n++;
804
		if (2 * dn > umax) break;	n++;
834
		if (2 * dn > umax) break;	n++;
805
		if (5 * dn > umax) break;	n++;
835
		if (5 * dn > umax) break;	n++;
806
		dn *= 10;
836
		dn *= 10;
807
	    }
837
	    }
808
	    if (!n)
838
	    if (!n)
809
		error("log - axis(), 'at' creation, _SMALL_ range: "
839
		error("log - axis(), 'at' creation, _SMALL_ range: "
810
		      "illegal {xy}axp or par;\n"
840
		      "illegal {xy}axp or par;\n"
811
		      "	 axp[0]= %g, usr[0:1]=(%g,%g)",
841
		      "	 axp[0]= %g, usr[0:1]=(%g,%g)",
812
		      axp[0], umin,umax);
842
		      axp[0], umin,umax);
813
	    at = allocVector(REALSXP, n);
843
	    at = allocVector(REALSXP, n);
814
	    dn = axp[0];
844
	    dn = axp[0];
815
	    n = 0;
845
	    n = 0;
816
	    if (0.2 * dn >= umin) REAL(at)[n++] = 0.2 * dn;
846
	    if (0.2 * dn >= umin) REAL(at)[n++] = 0.2 * dn;
817
	    if (0.5 * dn >= umin) REAL(at)[n++] = 0.5 * dn;
847
	    if (0.5 * dn >= umin) REAL(at)[n++] = 0.5 * dn;
818
	    for (;;) {
848
	    for (;;) {
819
		if (dn > umax) break;		REAL(at)[n++] = dn;
849
		if (dn > umax) break;		REAL(at)[n++] = dn;
820
		if (2 * dn > umax) break;	REAL(at)[n++] = 2 * dn;
850
		if (2 * dn > umax) break;	REAL(at)[n++] = 2 * dn;
821
		if (5 * dn > umax) break;	REAL(at)[n++] = 5 * dn;
851
		if (5 * dn > umax) break;	REAL(at)[n++] = 5 * dn;
822
		dn *= 10;
852
		dn *= 10;
823
	    }
853
	    }
824
	    break;
854
	    break;
825
	default:
855
	default:
826
	    error("log - axis(), 'at' creation: ILLEGAL {xy}axp[3] = %g",
856
	    error("log - axis(), 'at' creation: ILLEGAL {xy}axp[3] = %g",
827
		  axp[2]);
857
		  axp[2]);
828
	}
858
	}
829
    }
859
    }
830
    return at;
860
    return at;
831
}
861
}
832
 
862
 
833
SEXP do_axis(SEXP call, SEXP op, SEXP args, SEXP env)
863
SEXP do_axis(SEXP call, SEXP op, SEXP args, SEXP env)
834
{
864
{
835
    /* axis(side, at, labels, tick, line, pos,
865
    /* axis(side, at, labels, tick, line, pos,
836
     *	    outer, font, vfont, lty, lwd, col, ...) */
866
     *	    outer, font, vfont, lty, lwd, col, ...) */
837
 
867
 
838
    SEXP at, lab, vfont;
868
    SEXP at, lab, vfont;
839
    int col, font, lty;
869
    int col, font, lty;
840
    int i, n, nint = 0, ntmp, side, *ind, outer, lineoff = 0;
870
    int i, n, nint = 0, ntmp, side, *ind, outer, lineoff = 0;
841
    int istart, iend, incr;
871
    int istart, iend, incr;
842
    Rboolean dolabels, doticks, logflag = FALSE;
872
    Rboolean dolabels, doticks, logflag = FALSE;
843
    Rboolean create_at, vectorFonts = FALSE;
873
    Rboolean create_at, vectorFonts = FALSE;
844
    double x, y, temp, tnew, tlast;
874
    double x, y, temp, tnew, tlast;
845
    double axp[3], usr[2];
875
    double axp[3], usr[2];
846
    double gap, labw, low, high, line, pos, lwd;
876
    double gap, labw, low, high, line, pos, lwd;
847
    double axis_base, axis_tick, axis_lab, axis_low, axis_high;
877
    double axis_base, axis_tick, axis_lab, axis_low, axis_high;
848
 
878
 
849
    SEXP originalArgs = args, label;
879
    SEXP originalArgs = args, label;
850
    DevDesc *dd = CurrentDevice();
880
    DevDesc *dd = CurrentDevice();
851
 
881
 
852
    /* Arity Check */
882
    /* Arity Check */
853
    /* This is a builtin function, so it should always have */
883
    /* This is a builtin function, so it should always have */
854
    /* the correct arity, but it doesn't hurt to be defensive. */
884
    /* the correct arity, but it doesn't hurt to be defensive. */
855
 
885
 
856
    if (length(args) < 9)
886
    if (length(args) < 9)
857
	errorcall(call, "too few arguments");
887
	errorcall(call, "too few arguments");
858
    GCheckState(dd);
888
    GCheckState(dd);
859
 
889
 
860
    /* Required argument: "side" */
890
    /* Required argument: "side" */
861
    /* Which side of the plot the axis is to appear on. */
891
    /* Which side of the plot the axis is to appear on. */
862
    /* side = 1 | 2 | 3 | 4. */
892
    /* side = 1 | 2 | 3 | 4. */
863
 
893
 
864
    side = asInteger(CAR(args));
894
    side = asInteger(CAR(args));
865
    if (side < 1 || side > 4)
895
    if (side < 1 || side > 4)
866
	errorcall(call, "invalid axis number %d", side);
896
	errorcall(call, "invalid axis number %d", side);
867
    args = CDR(args);
897
    args = CDR(args);
868
 
898
 
869
    /* Required argument: "at" */
899
    /* Required argument: "at" */
870
    /* This gives the tick-label locations. */
900
    /* This gives the tick-label locations. */
871
    /* Note that these are coerced to the correct type below. */
901
    /* Note that these are coerced to the correct type below. */
872
 
902
 
873
    at = CAR(args); args = CDR(args);
903
    at = CAR(args); args = CDR(args);
874
 
904
 
875
    /* Required argument: "labels" */
905
    /* Required argument: "labels" */
876
    /* Labels can be a logical, indicating whether or not */
906
    /* Labels can be a logical, indicating whether or not */
877
    /* to label the axis; or it can be a vector of character */
907
    /* to label the axis; or it can be a vector of character */
878
    /* strings or expressions which give the labels explicitly. */
908
    /* strings or expressions which give the labels explicitly. */
879
    /* The expressions are used to set mathematical labelling. */
909
    /* The expressions are used to set mathematical labelling. */
880
 
910
 
881
    dolabels = TRUE;
911
    dolabels = TRUE;
882
    if (isLogical(CAR(args)) && length(CAR(args)) > 0) {
912
    if (isLogical(CAR(args)) && length(CAR(args)) > 0) {
883
	i = asLogical(CAR(args));
913
	i = asLogical(CAR(args));
884
	if (i == 0 || i == NA_LOGICAL)
914
	if (i == 0 || i == NA_LOGICAL)
885
	    dolabels = FALSE;
915
	    dolabels = FALSE;
886
	PROTECT(lab = R_NilValue);
916
	PROTECT(lab = R_NilValue);
887
    }
917
    }
888
    else if (isExpression(CAR(args))) {
918
    else if (isExpression(CAR(args))) {
889
	PROTECT(lab = CAR(args));
919
	PROTECT(lab = CAR(args));
890
    }
920
    }
891
    else {
921
    else {
892
	PROTECT(lab = coerceVector(CAR(args), STRSXP));
922
	PROTECT(lab = coerceVector(CAR(args), STRSXP));
893
    }
923
    }
894
    args = CDR(args);
924
    args = CDR(args);
895
 
925
 
896
    /* Required argument: "tick" */
926
    /* Required argument: "tick" */
897
    /* This indicates whether or not ticks and the axis line */
927
    /* This indicates whether or not ticks and the axis line */
898
    /* should be plotted: TRUE => show, FALSE => don't show. */
928
    /* should be plotted: TRUE => show, FALSE => don't show. */
899
 
929
 
900
    doticks = asLogical(CAR(args));
930
    doticks = asLogical(CAR(args));
901
    doticks = (doticks == NA_LOGICAL) ? TRUE : (Rboolean) doticks;
931
    doticks = (doticks == NA_LOGICAL) ? TRUE : (Rboolean) doticks;
902
    args = CDR(args);
932
    args = CDR(args);
903
 
933
 
904
    /* Optional argument: "line" */
934
    /* Optional argument: "line" */
905
 
935
 
906
    /* Specifies an offset outward from the plot for the axis.
936
    /* Specifies an offset outward from the plot for the axis.
907
     * The values in the par value "mgp" are interpreted
937
     * The values in the par value "mgp" are interpreted
908
     * relative to this value. */
938
     * relative to this value. */
909
    line = asReal(CAR(args));
939
    line = asReal(CAR(args));
910
    if (!R_FINITE(line)) {
940
    if (!R_FINITE(line)) {
911
	/* Except that here mgp values are not relative to themselves */
941
	/* Except that here mgp values are not relative to themselves */
912
	line = Rf_gpptr(dd)->mgp[2];
942
	line = Rf_gpptr(dd)->mgp[2];
913
	lineoff = line;
943
	lineoff = line;
914
    }
944
    }
915
    args = CDR(args);
945
    args = CDR(args);
916
 
946
 
917
    /* Optional argument: "pos" */
947
    /* Optional argument: "pos" */
918
    /* Specifies a user coordinate at which the axis should be drawn. */
948
    /* Specifies a user coordinate at which the axis should be drawn. */
919
    /* This overrides the value of "line".  Again the "mgp" par values */
949
    /* This overrides the value of "line".  Again the "mgp" par values */
920
    /* are interpreted relative to this value. */
950
    /* are interpreted relative to this value. */
921
 
951
 
922
    pos = asReal(CAR(args));
952
    pos = asReal(CAR(args));
923
    if (!R_FINITE(pos)) pos = NA_REAL; else lineoff = 0;
953
    if (!R_FINITE(pos)) pos = NA_REAL; else lineoff = 0;
924
    args = CDR(args);
954
    args = CDR(args);
925
 
955
 
926
    /* Optional argument: "outer" */
956
    /* Optional argument: "outer" */
927
    /* Should the axis be drawn in the outer margin. */
957
    /* Should the axis be drawn in the outer margin. */
928
    /* This only affects the computation of axis_base. */
958
    /* This only affects the computation of axis_base. */
929
 
959
 
930
    outer = asLogical(CAR(args));
960
    outer = asLogical(CAR(args));
931
    if (outer == NA_LOGICAL || outer == 0)
961
    if (outer == NA_LOGICAL || outer == 0)
932
	outer = NPC;
962
	outer = NPC;
933
    else
963
    else
934
	outer = NIC;
964
	outer = NIC;
935
    args = CDR(args);
965
    args = CDR(args);
936
 
966
 
937
    /* Optional argument: "font" */
967
    /* Optional argument: "font" */
938
    font = asInteger(FixupFont(CAR(args), NA_INTEGER));
968
    font = asInteger(FixupFont(CAR(args), NA_INTEGER));
939
    args = CDR(args);
969
    args = CDR(args);
940
 
970
 
941
    /* Optional argument: "vfont" */
971
    /* Optional argument: "vfont" */
942
    /* Allows Hershey vector fonts to be used */
972
    /* Allows Hershey vector fonts to be used */
943
    PROTECT(vfont = FixupVFont(CAR(args)));
973
    PROTECT(vfont = FixupVFont(CAR(args)));
944
    if (!isNull(vfont))
974
    if (!isNull(vfont))
945
	vectorFonts = TRUE;
975
	vectorFonts = TRUE;
946
    args = CDR(args);
976
    args = CDR(args);
947
 
977
 
948
    /* Optional argument: "lty" */
978
    /* Optional argument: "lty" */
949
    lty = asInteger(FixupLty(CAR(args), NA_INTEGER));
979
    lty = asInteger(FixupLty(CAR(args), NA_INTEGER));
950
    args = CDR(args);
980
    args = CDR(args);
951
 
981
 
952
    /* Optional argument: "lwd" */
982
    /* Optional argument: "lwd" */
953
    lwd = asReal(FixupLwd(CAR(args), Rf_gpptr(dd)->lwd));
983
    lwd = asReal(FixupLwd(CAR(args), Rf_gpptr(dd)->lwd));
954
    args = CDR(args);
984
    args = CDR(args);
955
 
985
 
956
    /* Optional argument: "col" */
986
    /* Optional argument: "col" */
957
    col = asInteger(FixupCol(CAR(args), Rf_gpptr(dd)->fg));
987
    col = asInteger(FixupCol(CAR(args), Rf_gpptr(dd)->fg));
958
    args = CDR(args);
988
    args = CDR(args);
959
 
989
 
960
    /* Retrieve relevant "par" values. */
990
    /* Retrieve relevant "par" values. */
961
 
991
 
962
    switch(side) {
992
    switch(side) {
963
    case 1:
993
    case 1:
964
    case 3:
994
    case 3:
965
	axp[0] = Rf_dpptr(dd)->xaxp[0];
995
	axp[0] = Rf_dpptr(dd)->xaxp[0];
966
	axp[1] = Rf_dpptr(dd)->xaxp[1];
996
	axp[1] = Rf_dpptr(dd)->xaxp[1];
967
	axp[2] = Rf_dpptr(dd)->xaxp[2];
997
	axp[2] = Rf_dpptr(dd)->xaxp[2];
968
	usr[0] = Rf_dpptr(dd)->usr[0];
998
	usr[0] = Rf_dpptr(dd)->usr[0];
969
	usr[1] = Rf_dpptr(dd)->usr[1];
999
	usr[1] = Rf_dpptr(dd)->usr[1];
970
	logflag = Rf_dpptr(dd)->xlog;
1000
	logflag = Rf_dpptr(dd)->xlog;
971
	nint = Rf_dpptr(dd)->lab[0];
1001
	nint = Rf_dpptr(dd)->lab[0];
972
	break;
1002
	break;
973
    case 2:
1003
    case 2:
974
    case 4:
1004
    case 4:
975
	axp[0] = Rf_dpptr(dd)->yaxp[0];
1005
	axp[0] = Rf_dpptr(dd)->yaxp[0];
976
	axp[1] = Rf_dpptr(dd)->yaxp[1];
1006
	axp[1] = Rf_dpptr(dd)->yaxp[1];
977
	axp[2] = Rf_dpptr(dd)->yaxp[2];
1007
	axp[2] = Rf_dpptr(dd)->yaxp[2];
978
	usr[0] = Rf_dpptr(dd)->usr[2];
1008
	usr[0] = Rf_dpptr(dd)->usr[2];
979
	usr[1] = Rf_dpptr(dd)->usr[3];
1009
	usr[1] = Rf_dpptr(dd)->usr[3];
980
	logflag = Rf_dpptr(dd)->ylog;
1010
	logflag = Rf_dpptr(dd)->ylog;
981
	nint = Rf_dpptr(dd)->lab[1];
1011
	nint = Rf_dpptr(dd)->lab[1];
982
	break;
1012
	break;
983
    }
1013
    }
984
 
1014
 
985
    /* Determine the tickmark positions.  Note that these may fall */
1015
    /* Determine the tickmark positions.  Note that these may fall */
986
    /* outside the plot window. We will clip them in the code below. */
1016
    /* outside the plot window. We will clip them in the code below. */
987
 
1017
 
988
    create_at = (length(at) == 0);
1018
    create_at = (length(at) == 0);
989
    if (create_at) {
1019
    if (create_at) {
990
	PROTECT(at = CreateAtVector(axp, usr, nint, logflag));
1020
	PROTECT(at = CreateAtVector(axp, usr, nint, logflag));
991
    }
1021
    }
992
    else {
1022
    else {
993
	if (isReal(at)) PROTECT(at = duplicate(at));
1023
	if (isReal(at)) PROTECT(at = duplicate(at));
994
	else PROTECT(at = coerceVector(at, REALSXP));
1024
	else PROTECT(at = coerceVector(at, REALSXP));
995
    }
1025
    }
996
    n = length(at);
1026
    n = length(at);
997
 
1027
 
998
    /* Check/setup the tick labels.  This can mean using user-specified */
1028
    /* Check/setup the tick labels.  This can mean using user-specified */
999
    /* labels, or encoding the "at" positions as strings. */
1029
    /* labels, or encoding the "at" positions as strings. */
1000
 
1030
 
1001
    if (dolabels) {
1031
    if (dolabels) {
1002
	if (length(lab) == 0)
1032
	if (length(lab) == 0)
1003
	    lab = labelformat(at);
1033
	    lab = labelformat(at);
1004
	else if (!isExpression(lab))
1034
	else if (!isExpression(lab))
1005
	    lab = labelformat(lab);
1035
	    lab = labelformat(lab);
1006
	if (length(at) != length(lab))
1036
	if (length(at) != length(lab))
1007
	    errorcall(call, "location and label lengths differ, %d != %d",
1037
	    errorcall(call, "location and label lengths differ, %d != %d",
1008
		      length(at), length(lab));
1038
		      length(at), length(lab));
1009
    }
1039
    }
1010
    PROTECT(lab);
1040
    PROTECT(lab);
1011
 
1041
 
1012
    /* Check there are no NA, Inf or -Inf values for tick positions. */
1042
    /* Check there are no NA, Inf or -Inf values for tick positions. */
1013
    /* The code here is long-winded.  Couldn't we just inline things */
1043
    /* The code here is long-winded.  Couldn't we just inline things */
1014
    /* below.  Hmmm - we need the min and max of the finite values ... */
1044
    /* below.  Hmmm - we need the min and max of the finite values ... */
1015
 
1045
 
1016
    ind = (int *) R_alloc(n, sizeof(int));
1046
    ind = (int *) R_alloc(n, sizeof(int));
1017
    for(i = 0; i < n; i++) ind[i] = i;
1047
    for(i = 0; i < n; i++) ind[i] = i;
1018
    rsort_with_index(REAL(at), ind, n);
1048
    rsort_with_index(REAL(at), ind, n);
1019
    ntmp = 0;
1049
    ntmp = 0;
1020
    for(i = 0; i < n; i++) {
1050
    for(i = 0; i < n; i++) {
1021
	if(R_FINITE(REAL(at)[i])) ntmp = i+1;
1051
	if(R_FINITE(REAL(at)[i])) ntmp = i+1;
1022
    }
1052
    }
1023
    n = ntmp;
1053
    n = ntmp;
1024
    if (n == 0)
1054
    if (n == 0)
1025
	errorcall(call, "no locations are finite");
1055
	errorcall(call, "no locations are finite");
1026
 
1056
 
1027
    /* Ok, all systems are "GO".  Let's get to it.
1057
    /* Ok, all systems are "GO".  Let's get to it.
1028
     * First we process all the remaining inline par values */
1058
     * First we process all the remaining inline par values */
1029
    GSavePars(dd);
1059
    GSavePars(dd);
1030
    ProcessInlinePars(args, dd, call);
1060
    ProcessInlinePars(args, dd, call);
1031
 
1061
 
1032
    /* At this point we know the value of "xaxt" and "yaxt",
1062
    /* At this point we know the value of "xaxt" and "yaxt",
1033
     * so we test to see whether the relevant one is "n".
1063
     * so we test to see whether the relevant one is "n".
1034
     * If it is, we just bail out at this point. */
1064
     * If it is, we just bail out at this point. */
1035
 
1065
 
1036
    if (((side == 1 || side == 3) && Rf_gpptr(dd)->xaxt == 'n') ||
1066
    if (((side == 1 || side == 3) && Rf_gpptr(dd)->xaxt == 'n') ||
1037
	((side == 2 || side == 4) && Rf_gpptr(dd)->yaxt == 'n')) {
1067
	((side == 2 || side == 4) && Rf_gpptr(dd)->yaxt == 'n')) {
1038
	GRestorePars(dd);
1068
	GRestorePars(dd);
1039
	UNPROTECT(4);
1069
	UNPROTECT(4);
1040
	return R_NilValue;
1070
	return R_NilValue;
1041
    }
1071
    }
1042
 
1072
 
1043
 
1073
 
1044
    /* no! we do allow an `lty' argument -- will not be used often though
1074
    /* no! we do allow an `lty' argument -- will not be used often though
1045
     *	Rf_gpptr(dd)->lty = LTY_SOLID; */
1075
     *	Rf_gpptr(dd)->lty = LTY_SOLID; */
1046
    Rf_gpptr(dd)->lty = lty;
1076
    Rf_gpptr(dd)->lty = lty;
1047
    Rf_gpptr(dd)->lwd = lwd;
1077
    Rf_gpptr(dd)->lwd = lwd;
1048
 
1078
 
1049
    /* Override par("xpd") and force clipping to figure region.
1079
    /* Override par("xpd") and force clipping to figure region.
1050
     * NOTE: don't override to _reduce_ clipping region */
1080
     * NOTE: don't override to _reduce_ clipping region */
1051
 
1081
 
1052
    Rf_gpptr(dd)->xpd = 2;
1082
    Rf_gpptr(dd)->xpd = 2;
1053
 
1083
 
1054
    Rf_gpptr(dd)->adj = 0.5;
1084
    Rf_gpptr(dd)->adj = 0.5;
1055
    Rf_gpptr(dd)->font = (font == NA_INTEGER)? Rf_gpptr(dd)->fontaxis : font;
1085
    Rf_gpptr(dd)->font = (font == NA_INTEGER)? Rf_gpptr(dd)->fontaxis : font;
1056
    Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * Rf_gpptr(dd)->cexaxis;
1086
    Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * Rf_gpptr(dd)->cexaxis;
1057
    /* no!   col = Rf_gpptr(dd)->col; */
1087
    /* no!   col = Rf_gpptr(dd)->col; */
1058
 
1088
 
1059
    /* Draw the axis */
1089
    /* Draw the axis */
1060
    GMode(1, dd);
1090
    GMode(1, dd);
1061
    switch (side) {
1091
    switch (side) {
1062
    case 1: /*--- x-axis -- horizontal --- */
1092
    case 1: /*--- x-axis -- horizontal --- */
1063
    case 3:
1093
    case 3:
1064
	GetAxisLimits(Rf_gpptr(dd)->usr[0], Rf_gpptr(dd)->usr[1], &low, &high);
1094
	GetAxisLimits(Rf_gpptr(dd)->usr[0], Rf_gpptr(dd)->usr[1], &low, &high);
1065
	axis_low  = GConvertX(fmax2(low, REAL(at)[0]), USER, NFC, dd);
1095
	axis_low  = GConvertX(fmax2(low, REAL(at)[0]), USER, NFC, dd);
1066
	axis_high = GConvertX(fmin2(high, REAL(at)[n-1]), USER, NFC, dd);
1096
	axis_high = GConvertX(fmin2(high, REAL(at)[n-1]), USER, NFC, dd);
1067
	if (side == 1) {
1097
	if (side == 1) {
1068
	    if (R_FINITE(pos))
1098
	    if (R_FINITE(pos))
1069
		axis_base = GConvertY(pos, USER, NFC, dd);
1099
		axis_base = GConvertY(pos, USER, NFC, dd);
1070
	    else
1100
	    else
1071
		axis_base = GConvertY(0.0, outer, NFC, dd)
1101
		axis_base = GConvertY(0.0, outer, NFC, dd)
1072
		    - GConvertYUnits(line, LINES, NFC, dd);
1102
		    - GConvertYUnits(line, LINES, NFC, dd);
1073
	    if (R_FINITE(Rf_gpptr(dd)->tck)) {
1103
	    if (R_FINITE(Rf_gpptr(dd)->tck)) {
1074
		double len, xu, yu;
1104
		double len, xu, yu;
1075
		if(Rf_gpptr(dd)->tck > 0.5)
1105
		if(Rf_gpptr(dd)->tck > 0.5)
1076
		    len = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, NFC, dd);
1106
		    len = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, NFC, dd);
1077
		else {
1107
		else {
1078
		    xu = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1108
		    xu = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1079
		    yu = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1109
		    yu = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1080
		    xu = (fabs(xu) < fabs(yu)) ? xu : yu;
1110
		    xu = (fabs(xu) < fabs(yu)) ? xu : yu;
1081
		    len = GConvertYUnits(xu, INCHES, NFC, dd);
1111
		    len = GConvertYUnits(xu, INCHES, NFC, dd);
1082
		}
1112
		}
1083
		axis_tick = axis_base + len;
1113
		axis_tick = axis_base + len;
1084
 
1114
 
1085
	    } else
1115
	    } else
1086
		axis_tick = axis_base +
1116
		axis_tick = axis_base +
1087
			GConvertYUnits(Rf_gpptr(dd)->tcl, LINES, NFC, dd);
1117
			GConvertYUnits(Rf_gpptr(dd)->tcl, LINES, NFC, dd);
1088
	}
1118
	}
1089
	else {
1119
	else {
1090
	    if (R_FINITE(pos))
1120
	    if (R_FINITE(pos))
1091
		axis_base = GConvertY(pos, USER, NFC, dd);
1121
		axis_base = GConvertY(pos, USER, NFC, dd);
1092
	    else
1122
	    else
1093
		axis_base =  GConvertY(1.0, outer, NFC, dd)
1123
		axis_base =  GConvertY(1.0, outer, NFC, dd)
1094
		    + GConvertYUnits(line, LINES, NFC, dd);
1124
		    + GConvertYUnits(line, LINES, NFC, dd);
1095
	    if (R_FINITE(Rf_gpptr(dd)->tck)) {
1125
	    if (R_FINITE(Rf_gpptr(dd)->tck)) {
1096
		double len, xu, yu;
1126
		double len, xu, yu;
1097
		if(Rf_gpptr(dd)->tck > 0.5)
1127
		if(Rf_gpptr(dd)->tck > 0.5)
1098
		    len = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, NFC, dd);
1128
		    len = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, NFC, dd);
1099
		else {
1129
		else {
1100
		    xu = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1130
		    xu = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1101
		    yu = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1131
		    yu = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1102
		    xu = (fabs(xu) < fabs(yu)) ? xu : yu;
1132
		    xu = (fabs(xu) < fabs(yu)) ? xu : yu;
1103
		    len = GConvertYUnits(xu, INCHES, NFC, dd);
1133
		    len = GConvertYUnits(xu, INCHES, NFC, dd);
1104
		}
1134
		}
1105
		axis_tick = axis_base - len;
1135
		axis_tick = axis_base - len;
1106
	    } else
1136
	    } else
1107
		axis_tick = axis_base -
1137
		axis_tick = axis_base -
1108
		    GConvertYUnits(Rf_gpptr(dd)->tcl, LINES, NFC, dd);
1138
		    GConvertYUnits(Rf_gpptr(dd)->tcl, LINES, NFC, dd);
1109
	}
1139
	}
1110
	if (doticks) {
1140
	if (doticks) {
1111
	    Rf_gpptr(dd)->col = col;/*was fg */
1141
	    Rf_gpptr(dd)->col = col;/*was fg */
1112
	    GLine(axis_low, axis_base, axis_high, axis_base, NFC, dd);
1142
	    GLine(axis_low, axis_base, axis_high, axis_base, NFC, dd);
1113
	    for (i = 0; i < n; i++) {
1143
	    for (i = 0; i < n; i++) {
1114
		x = REAL(at)[i];
1144
		x = REAL(at)[i];
1115
		if (low <= x && x <= high) {
1145
		if (low <= x && x <= high) {
1116
		    x = GConvertX(x, USER, NFC, dd);
1146
		    x = GConvertX(x, USER, NFC, dd);
1117
		    GLine(x, axis_base, x, axis_tick, NFC, dd);
1147
		    GLine(x, axis_base, x, axis_tick, NFC, dd);
1118
		}
1148
		}
1119
	    }
1149
	    }
1120
	}
1150
	}
1121
	/* Tickmark labels. */
1151
	/* Tickmark labels. */
1122
	Rf_gpptr(dd)->col = Rf_gpptr(dd)->colaxis;
1152
	Rf_gpptr(dd)->col = Rf_gpptr(dd)->colaxis;
1123
	gap = GStrWidth("m", NFC, dd);	/* FIXUP x/y distance */
1153
	gap = GStrWidth("m", NFC, dd);	/* FIXUP x/y distance */
1124
	tlast = -1.0;
1154
	tlast = -1.0;
1125
	if (Rf_gpptr(dd)->las == 2 || Rf_gpptr(dd)->las == 3) {
1155
	if (Rf_gpptr(dd)->las == 2 || Rf_gpptr(dd)->las == 3) {
1126
	    Rf_gpptr(dd)->adj = (side == 1) ? 1 : 0;
1156
	    Rf_gpptr(dd)->adj = (side == 1) ? 1 : 0;
1127
	}
1157
	}
1128
	else Rf_gpptr(dd)->adj = 0.5;
1158
	else Rf_gpptr(dd)->adj = 0.5;
1129
	if (side == 1) {
1159
	if (side == 1) {
1130
	    axis_lab = - axis_base
1160
	    axis_lab = - axis_base
1131
		+ GConvertYUnits(Rf_gpptr(dd)->mgp[1]-lineoff, LINES, NFC, dd)
1161
		+ GConvertYUnits(Rf_gpptr(dd)->mgp[1]-lineoff, LINES, NFC, dd)
1132
		+ GConvertY(0.0, NPC, NFC, dd);
1162
		+ GConvertY(0.0, NPC, NFC, dd);
1133
	}
1163
	}
1134
	else { /* side == 3 */
1164
	else { /* side == 3 */
1135
	    axis_lab = axis_base
1165
	    axis_lab = axis_base
1136
		+ GConvertYUnits(Rf_gpptr(dd)->mgp[1]-lineoff, LINES, NFC, dd)
1166
		+ GConvertYUnits(Rf_gpptr(dd)->mgp[1]-lineoff, LINES, NFC, dd)
1137
		- GConvertY(1.0, NPC, NFC, dd);
1167
		- GConvertY(1.0, NPC, NFC, dd);
1138
	}
1168
	}
1139
	axis_lab = GConvertYUnits(axis_lab, NFC, LINES, dd);
1169
	axis_lab = GConvertYUnits(axis_lab, NFC, LINES, dd);
1140
 
1170
 
1141
	/* The order of processing is important here. */
1171
	/* The order of processing is important here. */
1142
	/* We must ensure that the labels are drawn left-to-right. */
1172
	/* We must ensure that the labels are drawn left-to-right. */
1143
	/* The logic here is getting way too convoluted. */
1173
	/* The logic here is getting way too convoluted. */
1144
	/* This needs a serious rewrite. */
1174
	/* This needs a serious rewrite. */
1145
 
1175
 
1146
	if (Rf_gpptr(dd)->usr[0] > Rf_gpptr(dd)->usr[1]) {
1176
	if (Rf_gpptr(dd)->usr[0] > Rf_gpptr(dd)->usr[1]) {
1147
	    istart = n - 1;
1177
	    istart = n - 1;
1148
	    iend = -1;
1178
	    iend = -1;
1149
	    incr = -1;
1179
	    incr = -1;
1150
	}
1180
	}
1151
	else {
1181
	else {
1152
	    istart = 0;
1182
	    istart = 0;
1153
	    iend = n;
1183
	    iend = n;
1154
	    incr = 1;
1184
	    incr = 1;
1155
	}
1185
	}
1156
	for (i = istart; i != iend; i += incr) {
1186
	for (i = istart; i != iend; i += incr) {
1157
	    x = REAL(at)[i];
1187
	    x = REAL(at)[i];
1158
	    if (!R_FINITE(x)) continue;
1188
	    if (!R_FINITE(x)) continue;
1159
	    temp = GConvertX(x, USER, NFC, dd);
1189
	    temp = GConvertX(x, USER, NFC, dd);
1160
	    if (dolabels) {
1190
	    if (dolabels) {
1161
		/* Clip tick labels to user coordinates. */
1191
		/* Clip tick labels to user coordinates. */
1162
		if (x > low && x < high) {
1192
		if (x > low && x < high) {
1163
		    if (isExpression(lab)) {
1193
		    if (isExpression(lab)) {
1164
			GMMathText(VECTOR_ELT(lab, ind[i]), side,
1194
			GMMathText(VECTOR_ELT(lab, ind[i]), side,
1165
				   axis_lab, 0, x, Rf_gpptr(dd)->las, dd);
1195
				   axis_lab, 0, x, Rf_gpptr(dd)->las, dd);
1166
		    }
1196
		    }
1167
		    else {
1197
		    else {
1168
			label = STRING_ELT(lab, ind[i]);
1198
			label = STRING_ELT(lab, ind[i]);
1169
			if(label != NA_STRING) {
1199
			if(label != NA_STRING) {
1170
			    labw = GStrWidth(CHAR(label), NFC, dd);
1200
			    labw = GStrWidth(CHAR(label), NFC, dd);
1171
			    tnew = temp - 0.5 * labw;
1201
			    tnew = temp - 0.5 * labw;
1172
			    /* Check room for perpendicular labels. */
1202
			    /* Check room for perpendicular labels. */
1173
			    if (Rf_gpptr(dd)->las == 2 ||
1203
			    if (Rf_gpptr(dd)->las == 2 ||
1174
				Rf_gpptr(dd)->las == 3 ||
1204
				Rf_gpptr(dd)->las == 3 ||
1175
				tnew - tlast >= gap) {
1205
				tnew - tlast >= gap) {
1176
				GMtext(CHAR(label), side, axis_lab, 0, x,
1206
				GMtext(CHAR(label), side, axis_lab, 0, x,
1177
				       Rf_gpptr(dd)->las, dd);
1207
				       Rf_gpptr(dd)->las, dd);
1178
				tlast = temp + 0.5 *labw;
1208
				tlast = temp + 0.5 *labw;
1179
			    }
1209
			    }
1180
			}
1210
			}
1181
		    }
1211
		    }
1182
		}
1212
		}
1183
	    }
1213
	    }
1184
	}
1214
	}
1185
	break;
1215
	break;
1186
 
1216
 
1187
    case 2: /*--- y-axis -- vertical --- */
1217
    case 2: /*--- y-axis -- vertical --- */
1188
    case 4:
1218
    case 4:
1189
	GetAxisLimits(Rf_gpptr(dd)->usr[2], Rf_gpptr(dd)->usr[3], &low, &high);
1219
	GetAxisLimits(Rf_gpptr(dd)->usr[2], Rf_gpptr(dd)->usr[3], &low, &high);
1190
	axis_low = GConvertY(fmax2(low, REAL(at)[0]), USER, NFC, dd);
1220
	axis_low = GConvertY(fmax2(low, REAL(at)[0]), USER, NFC, dd);
1191
	axis_high = GConvertY(fmin2(high, REAL(at)[n-1]), USER, NFC, dd);
1221
	axis_high = GConvertY(fmin2(high, REAL(at)[n-1]), USER, NFC, dd);
1192
	if (side == 2) {
1222
	if (side == 2) {
1193
	    if (R_FINITE(pos))
1223
	    if (R_FINITE(pos))
1194
		axis_base = GConvertX(pos, USER, NFC, dd);
1224
		axis_base = GConvertX(pos, USER, NFC, dd);
1195
	    else
1225
	    else
1196
		axis_base =  GConvertX(0.0, outer, NFC, dd)
1226
		axis_base =  GConvertX(0.0, outer, NFC, dd)
1197
		    - GConvertXUnits(line, LINES, NFC, dd);
1227
		    - GConvertXUnits(line, LINES, NFC, dd);
1198
	    if (R_FINITE(Rf_gpptr(dd)->tck)) {
1228
	    if (R_FINITE(Rf_gpptr(dd)->tck)) {
1199
		double len, xu, yu;
1229
		double len, xu, yu;
1200
		if(Rf_gpptr(dd)->tck > 0.5)
1230
		if(Rf_gpptr(dd)->tck > 0.5)
1201
		    len = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, NFC, dd);
1231
		    len = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, NFC, dd);
1202
		else {
1232
		else {
1203
		    xu = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1233
		    xu = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1204
		    yu = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1234
		    yu = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1205
		    xu = (fabs(xu) < fabs(yu)) ? xu : yu;
1235
		    xu = (fabs(xu) < fabs(yu)) ? xu : yu;
1206
		    len = GConvertXUnits(xu, INCHES, NFC, dd);
1236
		    len = GConvertXUnits(xu, INCHES, NFC, dd);
1207
		}
1237
		}
1208
		axis_tick = axis_base + len;
1238
		axis_tick = axis_base + len;
1209
	    } else
1239
	    } else
1210
		axis_tick = axis_base +
1240
		axis_tick = axis_base +
1211
		    GConvertXUnits(Rf_gpptr(dd)->tcl, LINES, NFC, dd);
1241
		    GConvertXUnits(Rf_gpptr(dd)->tcl, LINES, NFC, dd);
1212
	}
1242
	}
1213
	else {
1243
	else {
1214
	    if (R_FINITE(pos))
1244
	    if (R_FINITE(pos))
1215
		axis_base = GConvertX(pos, USER, NFC, dd);
1245
		axis_base = GConvertX(pos, USER, NFC, dd);
1216
	    else
1246
	    else
1217
		axis_base =  GConvertX(1.0, outer, NFC, dd)
1247
		axis_base =  GConvertX(1.0, outer, NFC, dd)
1218
		    + GConvertXUnits(line, LINES, NFC, dd);
1248
		    + GConvertXUnits(line, LINES, NFC, dd);
1219
	    if (R_FINITE(Rf_gpptr(dd)->tck)) {
1249
	    if (R_FINITE(Rf_gpptr(dd)->tck)) {
1220
		double len, xu, yu;
1250
		double len, xu, yu;
1221
		if(Rf_gpptr(dd)->tck > 0.5)
1251
		if(Rf_gpptr(dd)->tck > 0.5)
1222
		    len = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, NFC, dd);
1252
		    len = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, NFC, dd);
1223
		else {
1253
		else {
1224
		    xu = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1254
		    xu = GConvertXUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1225
		    yu = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1255
		    yu = GConvertYUnits(Rf_gpptr(dd)->tck, NPC, INCHES, dd);
1226
		    xu = (fabs(xu) < fabs(yu)) ? xu : yu;
1256
		    xu = (fabs(xu) < fabs(yu)) ? xu : yu;
1227
		    len = GConvertXUnits(xu, INCHES, NFC, dd);
1257
		    len = GConvertXUnits(xu, INCHES, NFC, dd);
1228
		}
1258
		}
1229
		axis_tick = axis_base - len;
1259
		axis_tick = axis_base - len;
1230
	    } else
1260
	    } else
1231
		axis_tick = axis_base -
1261
		axis_tick = axis_base -
1232
		    GConvertXUnits(Rf_gpptr(dd)->tcl, LINES, NFC, dd);
1262
		    GConvertXUnits(Rf_gpptr(dd)->tcl, LINES, NFC, dd);
1233
	}
1263
	}
1234
	if (doticks) {
1264
	if (doticks) {
1235
	    Rf_gpptr(dd)->col = col;/*was fg */
1265
	    Rf_gpptr(dd)->col = col;/*was fg */
1236
	    GLine(axis_base, axis_low, axis_base, axis_high, NFC, dd);
1266
	    GLine(axis_base, axis_low, axis_base, axis_high, NFC, dd);
1237
	    for (i = 0; i < n; i++) {
1267
	    for (i = 0; i < n; i++) {
1238
		y = REAL(at)[i];
1268
		y = REAL(at)[i];
1239
		if (low <= y && y <= high) {
1269
		if (low <= y && y <= high) {
1240
		    y = GConvertY(y, USER, NFC, dd);
1270
		    y = GConvertY(y, USER, NFC, dd);
1241
		    GLine(axis_base, y, axis_tick, y, NFC, dd);
1271
		    GLine(axis_base, y, axis_tick, y, NFC, dd);
1242
		}
1272
		}
1243
	    }
1273
	    }
1244
	}
1274
	}
1245
	/* Tickmark labels. */
1275
	/* Tickmark labels. */
1246
	Rf_gpptr(dd)->col = Rf_gpptr(dd)->colaxis;
1276
	Rf_gpptr(dd)->col = Rf_gpptr(dd)->colaxis;
1247
	gap = GStrWidth("m", INCHES, dd);
1277
	gap = GStrWidth("m", INCHES, dd);
1248
	gap = GConvertYUnits(gap, INCHES, NFC, dd);
1278
	gap = GConvertYUnits(gap, INCHES, NFC, dd);
1249
	tlast = -1.0;
1279
	tlast = -1.0;
1250
	if (Rf_gpptr(dd)->las == 1 || Rf_gpptr(dd)->las == 2) {
1280
	if (Rf_gpptr(dd)->las == 1 || Rf_gpptr(dd)->las == 2) {
1251
	    Rf_gpptr(dd)->adj = (side == 2) ? 1 : 0;
1281
	    Rf_gpptr(dd)->adj = (side == 2) ? 1 : 0;
1252
	}
1282
	}
1253
	else Rf_gpptr(dd)->adj = 0.5;
1283
	else Rf_gpptr(dd)->adj = 0.5;
1254
	if (side == 2) {
1284
	if (side == 2) {
1255
	    axis_lab = - axis_base
1285
	    axis_lab = - axis_base
1256
		+ GConvertXUnits(Rf_gpptr(dd)->mgp[1]-lineoff, LINES, NFC, dd)
1286
		+ GConvertXUnits(Rf_gpptr(dd)->mgp[1]-lineoff, LINES, NFC, dd)
1257
		+ GConvertX(0.0, NPC, NFC, dd);
1287
		+ GConvertX(0.0, NPC, NFC, dd);
1258
	}
1288
	}
1259
	else { /* side == 4 */
1289
	else { /* side == 4 */
1260
	    axis_lab = axis_base
1290
	    axis_lab = axis_base
1261
		+ GConvertXUnits(Rf_gpptr(dd)->mgp[1]-lineoff, LINES, NFC, dd)
1291
		+ GConvertXUnits(Rf_gpptr(dd)->mgp[1]-lineoff, LINES, NFC, dd)
1262
		- GConvertX(1.0, NPC, NFC, dd);
1292
		- GConvertX(1.0, NPC, NFC, dd);
1263
	}
1293
	}
1264
	axis_lab = GConvertXUnits(axis_lab, NFC, LINES, dd);
1294
	axis_lab = GConvertXUnits(axis_lab, NFC, LINES, dd);
1265
 
1295
 
1266
	/* The order of processing is important here. */
1296
	/* The order of processing is important here. */
1267
	/* We must ensure that the labels are drawn left-to-right. */
1297
	/* We must ensure that the labels are drawn left-to-right. */
1268
	/* The logic here is getting way too convoluted. */
1298
	/* The logic here is getting way too convoluted. */
1269
	/* This needs a serious rewrite. */
1299
	/* This needs a serious rewrite. */
1270
 
1300
 
1271
	if (Rf_gpptr(dd)->usr[2] > Rf_gpptr(dd)->usr[3]) {
1301
	if (Rf_gpptr(dd)->usr[2] > Rf_gpptr(dd)->usr[3]) {
1272
	    istart = n - 1;
1302
	    istart = n - 1;
1273
	    iend = -1;
1303
	    iend = -1;
1274
	    incr = -1;
1304
	    incr = -1;
1275
	}
1305
	}
1276
	else {
1306
	else {
1277
	    istart = 0;
1307
	    istart = 0;
1278
	    iend = n;
1308
	    iend = n;
1279
	    incr = 1;
1309
	    incr = 1;
1280
	}
1310
	}
1281
	for (i = istart; i != iend; i += incr) {
1311
	for (i = istart; i != iend; i += incr) {
1282
	    y = REAL(at)[i];
1312
	    y = REAL(at)[i];
1283
	    if (!R_FINITE(y)) continue;
1313
	    if (!R_FINITE(y)) continue;
1284
	    temp = GConvertY(y, USER, NFC, dd);
1314
	    temp = GConvertY(y, USER, NFC, dd);
1285
	    if (dolabels) {
1315
	    if (dolabels) {
1286
		/* Clip tick labels to user coordinates. */
1316
		/* Clip tick labels to user coordinates. */
1287
		if (y > low && y < high) {
1317
		if (y > low && y < high) {
1288
		    if (isExpression(lab)) {
1318
		    if (isExpression(lab)) {
1289
			GMMathText(VECTOR_ELT(lab, ind[i]), side,
1319
			GMMathText(VECTOR_ELT(lab, ind[i]), side,
1290
				   axis_lab, 0, y, Rf_gpptr(dd)->las, dd);
1320
				   axis_lab, 0, y, Rf_gpptr(dd)->las, dd);
1291
		    }
1321
		    }
1292
		    else {
1322
		    else {
1293
			label = STRING_ELT(lab, ind[i]);
1323
			label = STRING_ELT(lab, ind[i]);
1294
			if(label != NA_STRING) {
1324
			if(label != NA_STRING) {
1295
			    labw = GStrWidth(CHAR(label), INCHES, dd);
1325
			    labw = GStrWidth(CHAR(label), INCHES, dd);
1296
			    labw = GConvertYUnits(labw, INCHES, NFC, dd);
1326
			    labw = GConvertYUnits(labw, INCHES, NFC, dd);
1297
			    tnew = temp - 0.5 * labw;
1327
			    tnew = temp - 0.5 * labw;
1298
			    /* Check room for perpendicular labels. */
1328
			    /* Check room for perpendicular labels. */
1299
			    if (Rf_gpptr(dd)->las == 1 ||
1329
			    if (Rf_gpptr(dd)->las == 1 ||
1300
				Rf_gpptr(dd)->las == 2 ||
1330
				Rf_gpptr(dd)->las == 2 ||
1301
				tnew - tlast >= gap) {
1331
				tnew - tlast >= gap) {
1302
				GMtext(CHAR(label), side, axis_lab, 0, y,
1332
				GMtext(CHAR(label), side, axis_lab, 0, y,
1303
				       Rf_gpptr(dd)->las, dd);
1333
				       Rf_gpptr(dd)->las, dd);
1304
				tlast = temp + 0.5 *labw;
1334
				tlast = temp + 0.5 *labw;
1305
			    }
1335
			    }
1306
			}
1336
			}
1307
		    }
1337
		    }
1308
		}
1338
		}
1309
	    }
1339
	    }
1310
	}
1340
	}
1311
	break;
1341
	break;
1312
    } /* end  switch(side, ..) */
1342
    } /* end  switch(side, ..) */
1313
    UNPROTECT(4); /* lab, vfont, at, lab again */
1343
    UNPROTECT(4); /* lab, vfont, at, lab again */
1314
    GMode(0, dd);
1344
    GMode(0, dd);
1315
    GRestorePars(dd);
1345
    GRestorePars(dd);
1316
    /* NOTE: only record operation if no "error"  */
1346
    /* NOTE: only record operation if no "error"  */
1317
    if (GRecording(call))
1347
    if (GRecording(call))
1318
	recordGraphicOperation(op, originalArgs, dd);
1348
	recordGraphicOperation(op, originalArgs, dd);
1319
    return R_NilValue;
1349
    return R_NilValue;
1320
}/* do_axis */
1350
}/* do_axis */
1321
 
1351
 
1322
 
1352
 
1323
SEXP do_plot_xy(SEXP call, SEXP op, SEXP args, SEXP env)
1353
SEXP do_plot_xy(SEXP call, SEXP op, SEXP args, SEXP env)
1324
{
1354
{
1325
/*	plot.xy(xy, type, pch, lty, col, cex, ...)
1355
/*	plot.xy(xy, type, pch, lty, col, cex, ...)
1326
 
1356
 
1327
 *	plot points or lines of various types
1357
 *	plot points or lines of various types
1328
 */
1358
 */
1329
    SEXP sxy, sx, sy, pch, cex, col, bg, lty;
1359
    SEXP sxy, sx, sy, pch, cex, col, bg, lty;
1330
    double *x, *y, xold, yold, xx, yy, thiscex;
1360
    double *x, *y, xold, yold, xx, yy, thiscex;
1331
    int i, n, npch, ncex, ncol, nbg, nlty, type=0, start=0, thispch, thiscol;
1361
    int i, n, npch, ncex, ncol, nbg, nlty, type=0, start=0, thispch, thiscol;
1332
 
1362
 
1333
    SEXP originalArgs = args;
1363
    SEXP originalArgs = args;
1334
    DevDesc *dd = CurrentDevice();
1364
    DevDesc *dd = CurrentDevice();
1335
 
1365
 
1336
    /* Basic Checks */
1366
    /* Basic Checks */
1337
    GCheckState(dd);
1367
    GCheckState(dd);
1338
    if (length(args) < 6)
1368
    if (length(args) < 6)
1339
	errorcall(call, "too few arguments");
1369
	errorcall(call, "too few arguments");
1340
 
1370
 
1341
    /* Required Arguments */
1371
    /* Required Arguments */
1342
#define PLOT_XY_DEALING(subname)				\
1372
#define PLOT_XY_DEALING(subname)				\
1343
    sx = R_NilValue;		/* -Wall */			\
1373
    sx = R_NilValue;		/* -Wall */			\
1344
    sy = R_NilValue;		/* -Wall */			\
1374
    sy = R_NilValue;		/* -Wall */			\
1345
    sxy = CAR(args);						\
1375
    sxy = CAR(args);						\
1346
    if (isNewList(sxy) && length(sxy) >= 2) {			\
1376
    if (isNewList(sxy) && length(sxy) >= 2) {			\
1347
	internalTypeCheck(call, sx = VECTOR_ELT(sxy, 0), REALSXP);	\
1377
	internalTypeCheck(call, sx = VECTOR_ELT(sxy, 0), REALSXP);	\
1348
	internalTypeCheck(call, sy = VECTOR_ELT(sxy, 1), REALSXP);	\
1378
	internalTypeCheck(call, sy = VECTOR_ELT(sxy, 1), REALSXP);	\
1349
    }								\
1379
    }								\
1350
    else if (isList(sxy) && length(sxy) >= 2) {			\
1380
    else if (isList(sxy) && length(sxy) >= 2) {			\
1351
	internalTypeCheck(call, sx = CAR(sxy), REALSXP);	\
1381
	internalTypeCheck(call, sx = CAR(sxy), REALSXP);	\
1352
	internalTypeCheck(call, sy = CADR(sxy), REALSXP);	\
1382
	internalTypeCheck(call, sy = CADR(sxy), REALSXP);	\
1353
    }								\
1383
    }								\
1354
    else							\
1384
    else							\
1355
	errorcall(call, "invalid plotting structure");		\
1385
	errorcall(call, "invalid plotting structure");		\
1356
    if (LENGTH(sx) != LENGTH(sy))				\
1386
    if (LENGTH(sx) != LENGTH(sy))				\
1357
	error("x and y lengths differ in " subname "().");	\
1387
	error("x and y lengths differ in " subname "().");	\
1358
    n = LENGTH(sx);						\
1388
    n = LENGTH(sx);						\
1359
    args = CDR(args)
1389
    args = CDR(args)
1360
 
1390
 
1361
    PLOT_XY_DEALING("plot.xy");
1391
    PLOT_XY_DEALING("plot.xy");
1362
 
1392
 
1363
    if (isNull(CAR(args))) type = 'p';
1393
    if (isNull(CAR(args))) type = 'p';
1364
    else {
1394
    else {
1365
	if (isString(CAR(args)) && LENGTH(CAR(args)) == 1 &&
1395
	if (isString(CAR(args)) && LENGTH(CAR(args)) == 1 &&
1366
	    LENGTH(pch = STRING_ELT(CAR(args), 0)) >= 1) {
1396
	    LENGTH(pch = STRING_ELT(CAR(args), 0)) >= 1) {
1367
	    if(LENGTH(pch) > 1)
1397
	    if(LENGTH(pch) > 1)
1368
		warningcall(call, "plot type '%s' truncated to first character",
1398
		warningcall(call, "plot type '%s' truncated to first character",
1369
			    CHAR(pch));
1399
			    CHAR(pch));
1370
	    type = CHAR(pch)[0];
1400
	    type = CHAR(pch)[0];
1371
	}
1401
	}
1372
	else errorcall(call, "invalid plot type");
1402
	else errorcall(call, "invalid plot type");
1373
    }
1403
    }
1374
    args = CDR(args);
1404
    args = CDR(args);
1375
 
1405
 
1376
    PROTECT(pch = FixupPch(CAR(args), Rf_gpptr(dd)->pch));	args = CDR(args);
1406
    PROTECT(pch = FixupPch(CAR(args), Rf_gpptr(dd)->pch));	args = CDR(args);
1377
    npch = length(pch);
1407
    npch = length(pch);
1378
 
1408
 
1379
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));	args = CDR(args);
1409
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));	args = CDR(args);
1380
    nlty = length(lty);
1410
    nlty = length(lty);
1381
 
1411
 
1382
    /* Default col was NA_INTEGER (0x80000000) which was interpreted
1412
    /* Default col was NA_INTEGER (0x80000000) which was interpreted
1383
       as zero (black) or "don't draw" depending on line/rect/circle
1413
       as zero (black) or "don't draw" depending on line/rect/circle
1384
       situation. Now we set the default to zero and don't plot at all
1414
       situation. Now we set the default to zero and don't plot at all
1385
       if col==NA.
1415
       if col==NA.
1386
 
1416
 
1387
       FIXME: bg needs similar change, but that requires changes to
1417
       FIXME: bg needs similar change, but that requires changes to
1388
       the specific drivers. */
1418
       the specific drivers. */
1389
 
1419
 
1390
    PROTECT(col = FixupCol(CAR(args), 0)); args = CDR(args);
1420
    PROTECT(col = FixupCol(CAR(args), 0)); args = CDR(args);
1391
    ncol = LENGTH(col);
1421
    ncol = LENGTH(col);
1392
 
1422
 
1393
    PROTECT(bg = FixupCol(CAR(args), NA_INTEGER));	args = CDR(args);
1423
    PROTECT(bg = FixupCol(CAR(args), NA_INTEGER));	args = CDR(args);
1394
    nbg = LENGTH(bg);
1424
    nbg = LENGTH(bg);
1395
 
1425
 
1396
    PROTECT(cex = FixupCex(CAR(args), 1.0));	args = CDR(args);
1426
    PROTECT(cex = FixupCex(CAR(args), 1.0));	args = CDR(args);
1397
    ncex = LENGTH(cex);
1427
    ncex = LENGTH(cex);
1398
 
1428
 
1399
    /* Miscellaneous Graphical Parameters -- e.g., lwd */
1429
    /* Miscellaneous Graphical Parameters -- e.g., lwd */
1400
    GSavePars(dd);
1430
    GSavePars(dd);
1401
    ProcessInlinePars(args, dd, call);
1431
    ProcessInlinePars(args, dd, call);
1402
 
1432
 
1403
    x = REAL(sx);
1433
    x = REAL(sx);
1404
    y = REAL(sy);
1434
    y = REAL(sy);
1405
 
1435
 
1406
    if (nlty && INTEGER(lty)[0] != NA_INTEGER)
1436
    if (nlty && INTEGER(lty)[0] != NA_INTEGER)
1407
	Rf_gpptr(dd)->lty = INTEGER(lty)[0];
1437
	Rf_gpptr(dd)->lty = INTEGER(lty)[0];
1408
 
1438
 
1409
    GMode(1, dd);
1439
    GMode(1, dd);
1410
    /* removed by paul 26/5/99 because all clipping now happens in graphics.c
1440
    /* removed by paul 26/5/99 because all clipping now happens in graphics.c
1411
     * GClip(dd);
1441
     * GClip(dd);
1412
     */
1442
     */
1413
 
1443
 
1414
    switch(type) {
1444
    switch(type) {
1415
    case 'l':
1445
    case 'l':
1416
    case 'o':
1446
    case 'o':
1417
	/* lines and overplotted lines and points */
1447
	/* lines and overplotted lines and points */
1418
	Rf_gpptr(dd)->col = INTEGER(col)[0];
1448
	Rf_gpptr(dd)->col = INTEGER(col)[0];
1419
	xold = NA_REAL;
1449
	xold = NA_REAL;
1420
	yold = NA_REAL;
1450
	yold = NA_REAL;
1421
	for (i = 0; i < n; i++) {
1451
	for (i = 0; i < n; i++) {
1422
	    xx = x[i];
1452
	    xx = x[i];
1423
	    yy = y[i];
1453
	    yy = y[i];
1424
	    /* do the conversion now to check for non-finite */
1454
	    /* do the conversion now to check for non-finite */
1425
	    GConvert(&xx, &yy, USER, DEVICE, dd);
1455
	    GConvert(&xx, &yy, USER, DEVICE, dd);
1426
	    if ((R_FINITE(xx) && R_FINITE(yy)) &&
1456
	    if ((R_FINITE(xx) && R_FINITE(yy)) &&
1427
		!(R_FINITE(xold) && R_FINITE(yold)))
1457
		!(R_FINITE(xold) && R_FINITE(yold)))
1428
		start = i;
1458
		start = i;
1429
	    else if ((R_FINITE(xold) && R_FINITE(yold)) &&
1459
	    else if ((R_FINITE(xold) && R_FINITE(yold)) &&
1430
		     !(R_FINITE(xx) && R_FINITE(yy))) {
1460
		     !(R_FINITE(xx) && R_FINITE(yy))) {
1431
		if (i-start > 1)
1461
		if (i-start > 1)
1432
		    GPolyline(i-start, x+start, y+start,
1462
		    GPolyline(i-start, x+start, y+start,
1433
			      USER, dd);
1463
			      USER, dd);
1434
	    }
1464
	    }
1435
	    else if ((R_FINITE(xold) && R_FINITE(yold)) &&
1465
	    else if ((R_FINITE(xold) && R_FINITE(yold)) &&
1436
		     (i == n-1))
1466
		     (i == n-1))
1437
		GPolyline(n-start, x+start, y+start, USER, dd);
1467
		GPolyline(n-start, x+start, y+start, USER, dd);
1438
	    xold = xx;
1468
	    xold = xx;
1439
	    yold = yy;
1469
	    yold = yy;
1440
	}
1470
	}
1441
	break;
1471
	break;
1442
 
1472
 
1443
    case 'b':
1473
    case 'b':
1444
    case 'c': /* broken lines (with points in between if 'b') */
1474
    case 'c': /* broken lines (with points in between if 'b') */
1445
    {
1475
    {
1446
	double d, f;
1476
	double d, f;
1447
	d = GConvertYUnits(0.5, CHARS, INCHES, dd);
1477
	d = GConvertYUnits(0.5, CHARS, INCHES, dd);
1448
	Rf_gpptr(dd)->col = INTEGER(col)[0];
1478
	Rf_gpptr(dd)->col = INTEGER(col)[0];
1449
	xold = NA_REAL;
1479
	xold = NA_REAL;
1450
	yold = NA_REAL;
1480
	yold = NA_REAL;
1451
	for (i = 0; i < n; i++) {
1481
	for (i = 0; i < n; i++) {
1452
	    xx = x[i];
1482
	    xx = x[i];
1453
	    yy = y[i];
1483
	    yy = y[i];
1454
	    GConvert(&xx, &yy, USER, INCHES, dd);
1484
	    GConvert(&xx, &yy, USER, INCHES, dd);
1455
	    if (R_FINITE(xold) && R_FINITE(yold) &&
1485
	    if (R_FINITE(xold) && R_FINITE(yold) &&
1456
		R_FINITE(xx) && R_FINITE(yy)) {
1486
		R_FINITE(xx) && R_FINITE(yy)) {
1457
		if ((f = d/hypot(xx-xold, yy-yold)) < 0.5) {
1487
		if ((f = d/hypot(xx-xold, yy-yold)) < 0.5) {
1458
		    GLine(xold + f * (xx - xold),
1488
		    GLine(xold + f * (xx - xold),
1459
			  yold + f * (yy - yold),
1489
			  yold + f * (yy - yold),
1460
			  xx + f * (xold - xx),
1490
			  xx + f * (xold - xx),
1461
			  yy + f * (yold - yy),
1491
			  yy + f * (yold - yy),
1462
			  INCHES, dd);
1492
			  INCHES, dd);
1463
		}
1493
		}
1464
	    }
1494
	    }
1465
	    xold = xx;
1495
	    xold = xx;
1466
	    yold = yy;
1496
	    yold = yy;
1467
	}
1497
	}
1468
    }
1498
    }
1469
    break;
1499
    break;
1470
 
1500
 
1471
    case 's': /* step function	I */
1501
    case 's': /* step function	I */
1472
    {
1502
    {
1473
	double xtemp[3], ytemp[3];
1503
	double xtemp[3], ytemp[3];
1474
	Rf_gpptr(dd)->col = INTEGER(col)[0];
1504
	Rf_gpptr(dd)->col = INTEGER(col)[0];
1475
	xold = x[0];
1505
	xold = x[0];
1476
	yold = y[0];
1506
	yold = y[0];
1477
	GConvert(&xold, &yold, USER, DEVICE, dd);
1507
	GConvert(&xold, &yold, USER, DEVICE, dd);
1478
	for (i = 1; i < n; i++) {
1508
	for (i = 1; i < n; i++) {
1479
	    xx = x[i];
1509
	    xx = x[i];
1480
	    yy = y[i];
1510
	    yy = y[i];
1481
	    GConvert(&xx, &yy, USER, DEVICE, dd);
1511
	    GConvert(&xx, &yy, USER, DEVICE, dd);
1482
	    if (R_FINITE(xold) && R_FINITE(yold) &&
1512
	    if (R_FINITE(xold) && R_FINITE(yold) &&
1483
		R_FINITE(xx) && R_FINITE(yy)) {
1513
		R_FINITE(xx) && R_FINITE(yy)) {
1484
		xtemp[0] = xold; ytemp[0] = yold;
1514
		xtemp[0] = xold; ytemp[0] = yold;
1485
		xtemp[1] = xx;	ytemp[1] = yold;
1515
		xtemp[1] = xx;	ytemp[1] = yold;
1486
		xtemp[2] = xx;	ytemp[2] = yy;
1516
		xtemp[2] = xx;	ytemp[2] = yy;
1487
		GPolyline(3, xtemp, ytemp, DEVICE, dd);
1517
		GPolyline(3, xtemp, ytemp, DEVICE, dd);
1488
	    }
1518
	    }
1489
	    xold = xx;
1519
	    xold = xx;
1490
	    yold = yy;
1520
	    yold = yy;
1491
	}
1521
	}
1492
    }
1522
    }
1493
    break;
1523
    break;
1494
 
1524
 
1495
    case 'S': /* step function	II */
1525
    case 'S': /* step function	II */
1496
    {
1526
    {
1497
	double xtemp[3], ytemp[3];
1527
	double xtemp[3], ytemp[3];
1498
	Rf_gpptr(dd)->col = INTEGER(col)[0];
1528
	Rf_gpptr(dd)->col = INTEGER(col)[0];
1499
	xold = x[0];
1529
	xold = x[0];
1500
	yold = y[0];
1530
	yold = y[0];
1501
	GConvert(&xold, &yold, USER, DEVICE, dd);
1531
	GConvert(&xold, &yold, USER, DEVICE, dd);
1502
	for (i = 1; i < n; i++) {
1532
	for (i = 1; i < n; i++) {
1503
	    xx = x[i];
1533
	    xx = x[i];
1504
	    yy = y[i];
1534
	    yy = y[i];
1505
	    GConvert(&xx, &yy, USER, DEVICE, dd);
1535
	    GConvert(&xx, &yy, USER, DEVICE, dd);
1506
	    if (R_FINITE(xold) && R_FINITE(yold) &&
1536
	    if (R_FINITE(xold) && R_FINITE(yold) &&
1507
		R_FINITE(xx) && R_FINITE(yy)) {
1537
		R_FINITE(xx) && R_FINITE(yy)) {
1508
		xtemp[0] = xold; ytemp[0] = yold;
1538
		xtemp[0] = xold; ytemp[0] = yold;
1509
		xtemp[1] = xold; ytemp[1] = yy;
1539
		xtemp[1] = xold; ytemp[1] = yy;
1510
		xtemp[2] = xx; ytemp[2] = yy;
1540
		xtemp[2] = xx; ytemp[2] = yy;
1511
		GPolyline(3, xtemp, ytemp, DEVICE, dd);
1541
		GPolyline(3, xtemp, ytemp, DEVICE, dd);
1512
	    }
1542
	    }
1513
	    xold = xx;
1543
	    xold = xx;
1514
	    yold = yy;
1544
	    yold = yy;
1515
	}
1545
	}
1516
    }
1546
    }
1517
    break;
1547
    break;
1518
 
1548
 
1519
    case 'h': /* h[istogram] (bar plot) */
1549
    case 'h': /* h[istogram] (bar plot) */
1520
	if (Rf_gpptr(dd)->ylog)
1550
	if (Rf_gpptr(dd)->ylog)
1521
	    yold = Rf_gpptr(dd)->usr[2];/* DBL_MIN fails.. why ???? */
1551
	    yold = Rf_gpptr(dd)->usr[2];/* DBL_MIN fails.. why ???? */
1522
	else
1552
	else
1523
	    yold = 0.0;
1553
	    yold = 0.0;
1524
	yold = GConvertY(yold, USER, DEVICE, dd);
1554
	yold = GConvertY(yold, USER, DEVICE, dd);
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;
1536
 
1566
 
1537
    case 'p':
1567
    case 'p':
1538
    case 'n': /* nothing here */
1568
    case 'n': /* nothing here */
1539
	break;
1569
	break;
1540
 
1570
 
1541
    default:/* OTHERWISE */
1571
    default:/* OTHERWISE */
1542
	errorcall(call, "invalid plot type '%c'", type);
1572
	errorcall(call, "invalid plot type '%c'", type);
1543
 
1573
 
1544
    } /* End {switch(type)} */
1574
    } /* End {switch(type)} */
1545
 
1575
 
1546
    if (type == 'p' || type == 'b' || type == 'o') {
1576
    if (type == 'p' || type == 'b' || type == 'o') {
1547
	for (i = 0; i < n; i++) {
1577
	for (i = 0; i < n; i++) {
1548
	    xx = x[i];
1578
	    xx = x[i];
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);
1560
		}
1590
		}
1561
	    }
1591
	    }
1562
	}
1592
	}
1563
    }
1593
    }
1564
    GMode(0, dd);
1594
    GMode(0, dd);
1565
    GRestorePars(dd);
1595
    GRestorePars(dd);
1566
    UNPROTECT(5);
1596
    UNPROTECT(5);
1567
    /* NOTE: only record operation if no "error"  */
1597
    /* NOTE: only record operation if no "error"  */
1568
    if (GRecording(call))
1598
    if (GRecording(call))
1569
	recordGraphicOperation(op, originalArgs, dd);
1599
	recordGraphicOperation(op, originalArgs, dd);
1570
    return R_NilValue;
1600
    return R_NilValue;
1571
}/* do_plot_xy */
1601
}/* do_plot_xy */
1572
 
1602
 
1573
/* Checks for ... , x0, y0, x1, y1 ... */
1603
/* Checks for ... , x0, y0, x1, y1 ... */
1574
 
1604
 
1575
static void xypoints(SEXP call, SEXP args, int *n)
1605
static void xypoints(SEXP call, SEXP args, int *n)
1576
{
1606
{
1577
    int k=0;/* -Wall */
1607
    int k=0;/* -Wall */
1578
 
1608
 
1579
    if (!isNumeric(CAR(args)) || (k = LENGTH(CAR(args))) <= 0)
1609
    if (!isNumeric(CAR(args)) || (k = LENGTH(CAR(args))) <= 0)
1580
	errorcall(call, "first argument invalid");
1610
	errorcall(call, "first argument invalid");
1581
    SETCAR(args, coerceVector(CAR(args), REALSXP));
1611
    SETCAR(args, coerceVector(CAR(args), REALSXP));
1582
    *n = k;
1612
    *n = k;
1583
    args = CDR(args);
1613
    args = CDR(args);
1584
 
1614
 
1585
    if (!isNumeric(CAR(args)) || (k = LENGTH(CAR(args))) <= 0)
1615
    if (!isNumeric(CAR(args)) || (k = LENGTH(CAR(args))) <= 0)
1586
	errorcall(call, "second argument invalid");
1616
	errorcall(call, "second argument invalid");
1587
    SETCAR(args, coerceVector(CAR(args), REALSXP));
1617
    SETCAR(args, coerceVector(CAR(args), REALSXP));
1588
    if (k > *n) *n = k;
1618
    if (k > *n) *n = k;
1589
    args = CDR(args);
1619
    args = CDR(args);
1590
 
1620
 
1591
    if (!isNumeric(CAR(args)) || (k = LENGTH(CAR(args))) <= 0)
1621
    if (!isNumeric(CAR(args)) || (k = LENGTH(CAR(args))) <= 0)
1592
	errorcall(call, "third argument invalid");
1622
	errorcall(call, "third argument invalid");
1593
    SETCAR(args, coerceVector(CAR(args), REALSXP));
1623
    SETCAR(args, coerceVector(CAR(args), REALSXP));
1594
    if (k > *n) *n = k;
1624
    if (k > *n) *n = k;
1595
    args = CDR(args);
1625
    args = CDR(args);
1596
 
1626
 
1597
    if (!isNumeric(CAR(args)) || (k = LENGTH(CAR(args))) <= 0)
1627
    if (!isNumeric(CAR(args)) || (k = LENGTH(CAR(args))) <= 0)
1598
	errorcall(call, "fourth argument invalid");
1628
	errorcall(call, "fourth argument invalid");
1599
    SETCAR(args, coerceVector(CAR(args), REALSXP));
1629
    SETCAR(args, coerceVector(CAR(args), REALSXP));
1600
    if (k > *n) *n = k;
1630
    if (k > *n) *n = k;
1601
    args = CDR(args);
1631
    args = CDR(args);
1602
}
1632
}
1603
 
1633
 
1604
 
1634
 
1605
SEXP do_segments(SEXP call, SEXP op, SEXP args, SEXP env)
1635
SEXP do_segments(SEXP call, SEXP op, SEXP args, SEXP env)
1606
{
1636
{
1607
    /* segments(x0, y0, x1, y1, col, lty, lwd, ...) */
1637
    /* segments(x0, y0, x1, y1, col, lty, lwd, ...) */
1608
    SEXP sx0, sx1, sy0, sy1, col, lty, lwd;
1638
    SEXP sx0, sx1, sy0, sy1, col, lty, lwd;
1609
    double *x0, *x1, *y0, *y1;
1639
    double *x0, *x1, *y0, *y1;
1610
    double xx[2], yy[2];
1640
    double xx[2], yy[2];
1611
    int nx0, nx1, ny0, ny1, i, n, ncol, nlty, nlwd;
1641
    int nx0, nx1, ny0, ny1, i, n, ncol, nlty, nlwd;
1612
    SEXP originalArgs = args;
1642
    SEXP originalArgs = args;
1613
    DevDesc *dd = CurrentDevice();
1643
    DevDesc *dd = CurrentDevice();
1614
 
1644
 
1615
    if (length(args) < 4) errorcall(call, "too few arguments");
1645
    if (length(args) < 4) errorcall(call, "too few arguments");
1616
    GCheckState(dd);
1646
    GCheckState(dd);
1617
 
1647
 
1618
    xypoints(call, args, &n);
1648
    xypoints(call, args, &n);
1619
 
1649
 
1620
    sx0 = CAR(args); nx0 = length(sx0); args = CDR(args);
1650
    sx0 = CAR(args); nx0 = length(sx0); args = CDR(args);
1621
    sy0 = CAR(args); ny0 = length(sy0); args = CDR(args);
1651
    sy0 = CAR(args); ny0 = length(sy0); args = CDR(args);
1622
    sx1 = CAR(args); nx1 = length(sx1); args = CDR(args);
1652
    sx1 = CAR(args); nx1 = length(sx1); args = CDR(args);
1623
    sy1 = CAR(args); ny1 = length(sy1); args = CDR(args);
1653
    sy1 = CAR(args); ny1 = length(sy1); args = CDR(args);
1624
 
1654
 
1625
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));
1655
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));
1626
    ncol = LENGTH(col); args = CDR(args);
1656
    ncol = LENGTH(col); args = CDR(args);
1627
 
1657
 
1628
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));
1658
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));
1629
    nlty = length(lty); args = CDR(args);
1659
    nlty = length(lty); args = CDR(args);
1630
 
1660
 
1631
    PROTECT(lwd = FixupLwd(CAR(args), Rf_gpptr(dd)->lwd));
1661
    PROTECT(lwd = FixupLwd(CAR(args), Rf_gpptr(dd)->lwd));
1632
    nlwd = length(lwd); args = CDR(args);
1662
    nlwd = length(lwd); args = CDR(args);
1633
 
1663
 
1634
    GSavePars(dd);
1664
    GSavePars(dd);
1635
    ProcessInlinePars(args, dd, call);
1665
    ProcessInlinePars(args, dd, call);
1636
 
1666
 
1637
    x0 = REAL(sx0);
1667
    x0 = REAL(sx0);
1638
    y0 = REAL(sy0);
1668
    y0 = REAL(sy0);
1639
    x1 = REAL(sx1);
1669
    x1 = REAL(sx1);
1640
    y1 = REAL(sy1);
1670
    y1 = REAL(sy1);
1641
 
1671
 
1642
    GMode(1, dd);
1672
    GMode(1, dd);
1643
    for (i = 0; i < n; i++) {
1673
    for (i = 0; i < n; i++) {
1644
	xx[0] = x0[i%nx0];
1674
	xx[0] = x0[i%nx0];
1645
	yy[0] = y0[i%ny0];
1675
	yy[0] = y0[i%ny0];
1646
	xx[1] = x1[i%nx1];
1676
	xx[1] = x1[i%nx1];
1647
	yy[1] = y1[i%ny1];
1677
	yy[1] = y1[i%ny1];
1648
	GConvert(xx, yy, USER, DEVICE, dd);
1678
	GConvert(xx, yy, USER, DEVICE, dd);
1649
	GConvert(xx+1, yy+1, USER, DEVICE, dd);
1679
	GConvert(xx+1, yy+1, USER, DEVICE, dd);
1650
	if (R_FINITE(xx[0]) && R_FINITE(yy[0]) &&
1680
	if (R_FINITE(xx[0]) && R_FINITE(yy[0]) &&
1651
	    R_FINITE(xx[1]) && R_FINITE(yy[1]))
1681
	    R_FINITE(xx[1]) && R_FINITE(yy[1]))
1652
	{
1682
	{
1653
	    Rf_gpptr(dd)->col = INTEGER(col)[i % ncol];
1683
	    Rf_gpptr(dd)->col = INTEGER(col)[i % ncol];
1654
	    /* NA color should be ok */
1684
	    /* NA color should be ok */
1655
	    Rf_gpptr(dd)->lty = INTEGER(lty)[i % nlty];
1685
	    Rf_gpptr(dd)->lty = INTEGER(lty)[i % nlty];
1656
	    Rf_gpptr(dd)->lwd = REAL(lwd)[i % nlwd];
1686
	    Rf_gpptr(dd)->lwd = REAL(lwd)[i % nlwd];
1657
	    GLine(xx[0], yy[0], xx[1], yy[1], DEVICE, dd);
1687
	    GLine(xx[0], yy[0], xx[1], yy[1], DEVICE, dd);
1658
	}
1688
	}
1659
    }
1689
    }
1660
    GMode(0, dd);
1690
    GMode(0, dd);
1661
    GRestorePars(dd);
1691
    GRestorePars(dd);
1662
 
1692
 
1663
    UNPROTECT(3);
1693
    UNPROTECT(3);
1664
    /* NOTE: only record operation if no "error"  */
1694
    /* NOTE: only record operation if no "error"  */
1665
    if (GRecording(call))
1695
    if (GRecording(call))
1666
	recordGraphicOperation(op, originalArgs, dd);
1696
	recordGraphicOperation(op, originalArgs, dd);
1667
    return R_NilValue;
1697
    return R_NilValue;
1668
}
1698
}
1669
 
1699
 
1670
 
1700
 
1671
SEXP do_rect(SEXP call, SEXP op, SEXP args, SEXP env)
1701
SEXP do_rect(SEXP call, SEXP op, SEXP args, SEXP env)
1672
{
1702
{
1673
    /* rect(xl, yb, xr, yt, col, border, lty, lwd, xpd, ...) */
1703
    /* rect(xl, yb, xr, yt, col, border, lty, lwd, xpd, ...) */
1674
    SEXP sxl, sxr, syb, syt, sxpd, col, lty, lwd, border;
1704
    SEXP sxl, sxr, syb, syt, sxpd, col, lty, lwd, border;
1675
    double *xl, *xr, *yb, *yt, x0, y0, x1, y1;
1705
    double *xl, *xr, *yb, *yt, x0, y0, x1, y1;
1676
    int i, n, nxl, nxr, nyb, nyt, ncol, nlty, nlwd, nborder, xpd;
1706
    int i, n, nxl, nxr, nyb, nyt, ncol, nlty, nlwd, nborder, xpd;
1677
    SEXP originalArgs = args;
1707
    SEXP originalArgs = args;
1678
    DevDesc *dd = CurrentDevice();
1708
    DevDesc *dd = CurrentDevice();
1679
 
1709
 
1680
    if (length(args) < 4) errorcall(call, "too few arguments");
1710
    if (length(args) < 4) errorcall(call, "too few arguments");
1681
    GCheckState(dd);
1711
    GCheckState(dd);
1682
 
1712
 
1683
    xypoints(call, args, &n);
1713
    xypoints(call, args, &n);
1684
    sxl = CAR(args); nxl = length(sxl); args = CDR(args);/* x_left */
1714
    sxl = CAR(args); nxl = length(sxl); args = CDR(args);/* x_left */
1685
    syb = CAR(args); nyb = length(syb); args = CDR(args);/* y_bottom */
1715
    syb = CAR(args); nyb = length(syb); args = CDR(args);/* y_bottom */
1686
    sxr = CAR(args); nxr = length(sxr); args = CDR(args);/* x_right */
1716
    sxr = CAR(args); nxr = length(sxr); args = CDR(args);/* x_right */
1687
    syt = CAR(args); nyt = length(syt); args = CDR(args);/* y_top */
1717
    syt = CAR(args); nyt = length(syt); args = CDR(args);/* y_top */
1688
 
1718
 
1689
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));
1719
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));
1690
    ncol = LENGTH(col);
1720
    ncol = LENGTH(col);
1691
    args = CDR(args);
1721
    args = CDR(args);
1692
 
1722
 
1693
    PROTECT(border =  FixupCol(CAR(args), Rf_gpptr(dd)->fg));
1723
    PROTECT(border =  FixupCol(CAR(args), Rf_gpptr(dd)->fg));
1694
    nborder = LENGTH(border);
1724
    nborder = LENGTH(border);
1695
    args = CDR(args);
1725
    args = CDR(args);
1696
 
1726
 
1697
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));
1727
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));
1698
    nlty = length(lty);
1728
    nlty = length(lty);
1699
    args = CDR(args);
1729
    args = CDR(args);
1700
 
1730
 
1701
    PROTECT(lwd = FixupLwd(CAR(args), Rf_gpptr(dd)->lwd));
1731
    PROTECT(lwd = FixupLwd(CAR(args), Rf_gpptr(dd)->lwd));
1702
    nlwd = length(lwd);
1732
    nlwd = length(lwd);
1703
    args = CDR(args);
1733
    args = CDR(args);
1704
 
1734
 
1705
    sxpd = CAR(args);
1735
    sxpd = CAR(args);
1706
    if (sxpd != R_NilValue)
1736
    if (sxpd != R_NilValue)
1707
	xpd = asInteger(sxpd);
1737
	xpd = asInteger(sxpd);
1708
    else
1738
    else
1709
	xpd = Rf_gpptr(dd)->xpd;
1739
	xpd = Rf_gpptr(dd)->xpd;
1710
    args = CDR(args);
1740
    args = CDR(args);
1711
 
1741
 
1712
    GSavePars(dd);
1742
    GSavePars(dd);
1713
    ProcessInlinePars(args, dd, call);
1743
    ProcessInlinePars(args, dd, call);
1714
 
1744
 
1715
    if (xpd == NA_INTEGER)
1745
    if (xpd == NA_INTEGER)
1716
	Rf_gpptr(dd)->xpd = 2;
1746
	Rf_gpptr(dd)->xpd = 2;
1717
    else
1747
    else
1718
	Rf_gpptr(dd)->xpd = xpd;
1748
	Rf_gpptr(dd)->xpd = xpd;
1719
 
1749
 
1720
    xl = REAL(sxl);
1750
    xl = REAL(sxl);
1721
    xr = REAL(sxr);
1751
    xr = REAL(sxr);
1722
    yb = REAL(syb);
1752
    yb = REAL(syb);
1723
    yt = REAL(syt);
1753
    yt = REAL(syt);
1724
 
1754
 
1725
    GMode(1, dd);
1755
    GMode(1, dd);
1726
    for (i = 0; i < n; i++) {
1756
    for (i = 0; i < n; i++) {
1727
	if (nlty && INTEGER(lty)[i % nlty] != NA_INTEGER)
1757
	if (nlty && INTEGER(lty)[i % nlty] != NA_INTEGER)
1728
	    Rf_gpptr(dd)->lty = INTEGER(lty)[i % nlty];
1758
	    Rf_gpptr(dd)->lty = INTEGER(lty)[i % nlty];
1729
	else
1759
	else
1730
	    Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
1760
	    Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
1731
	if (nlwd && REAL(lwd)[i % nlwd] != NA_REAL)
1761
	if (nlwd && REAL(lwd)[i % nlwd] != NA_REAL)
1732
	    Rf_gpptr(dd)->lwd = REAL(lwd)[i % nlwd];
1762
	    Rf_gpptr(dd)->lwd = REAL(lwd)[i % nlwd];
1733
	else
1763
	else
1734
	    Rf_gpptr(dd)->lwd = Rf_dpptr(dd)->lwd;
1764
	    Rf_gpptr(dd)->lwd = Rf_dpptr(dd)->lwd;
1735
	x0 = xl[i%nxl];
1765
	x0 = xl[i%nxl];
1736
	y0 = yb[i%nyb];
1766
	y0 = yb[i%nyb];
1737
	x1 = xr[i%nxr];
1767
	x1 = xr[i%nxr];
1738
	y1 = yt[i%nyt];
1768
	y1 = yt[i%nyt];
1739
	GConvert(&x0, &y0, USER, DEVICE, dd);
1769
	GConvert(&x0, &y0, USER, DEVICE, dd);
1740
	GConvert(&x1, &y1, USER, DEVICE, dd);
1770
	GConvert(&x1, &y1, USER, DEVICE, dd);
1741
	if (R_FINITE(x0) && R_FINITE(y0) && R_FINITE(x1) && R_FINITE(y1))
1771
	if (R_FINITE(x0) && R_FINITE(y0) && R_FINITE(x1) && R_FINITE(y1))
1742
	    GRect(x0, y0, x1, y1, DEVICE, INTEGER(col)[i % ncol],
1772
	    GRect(x0, y0, x1, y1, DEVICE, INTEGER(col)[i % ncol],
1743
		  INTEGER(border)[i % nborder], dd);
1773
		  INTEGER(border)[i % nborder], dd);
1744
    }
1774
    }
1745
    GMode(0, dd);
1775
    GMode(0, dd);
1746
 
1776
 
1747
    GRestorePars(dd);
1777
    GRestorePars(dd);
1748
    UNPROTECT(4);
1778
    UNPROTECT(4);
1749
    /* NOTE: only record operation if no "error"  */
1779
    /* NOTE: only record operation if no "error"  */
1750
    if (GRecording(call))
1780
    if (GRecording(call))
1751
	recordGraphicOperation(op, originalArgs, dd);
1781
	recordGraphicOperation(op, originalArgs, dd);
1752
    return R_NilValue;
1782
    return R_NilValue;
1753
}
1783
}
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;
1765
    SEXP originalArgs = args;
1795
    SEXP originalArgs = args;
1766
    DevDesc *dd = CurrentDevice();
1796
    DevDesc *dd = CurrentDevice();
1767
 
1797
 
1768
    if (length(args) < 4) errorcall(call, "too few arguments");
1798
    if (length(args) < 4) errorcall(call, "too few arguments");
1769
    GCheckState(dd);
1799
    GCheckState(dd);
1770
 
1800
 
1771
    xypoints(call, args, &n);
1801
    xypoints(call, args, &n);
1772
 
1802
 
1773
    sx0 = CAR(args); nx0 = length(sx0); args = CDR(args);
1803
    sx0 = CAR(args); nx0 = length(sx0); args = CDR(args);
1774
    sy0 = CAR(args); ny0 = length(sy0); args = CDR(args);
1804
    sy0 = CAR(args); ny0 = length(sy0); args = CDR(args);
1775
    sx1 = CAR(args); nx1 = length(sx1); args = CDR(args);
1805
    sx1 = CAR(args); nx1 = length(sx1); args = CDR(args);
1776
    sy1 = CAR(args); ny1 = length(sy1); args = CDR(args);
1806
    sy1 = CAR(args); ny1 = length(sy1); args = CDR(args);
1777
 
1807
 
1778
    hlength = asReal(CAR(args));
1808
    hlength = asReal(CAR(args));
1779
    if (!R_FINITE(hlength) || hlength < 0)
1809
    if (!R_FINITE(hlength) || hlength < 0)
1780
	errorcall(call, "invalid head length");
1810
	errorcall(call, "invalid head length");
1781
    args = CDR(args);
1811
    args = CDR(args);
1782
 
1812
 
1783
    angle = asReal(CAR(args));
1813
    angle = asReal(CAR(args));
1784
    if (!R_FINITE(angle))
1814
    if (!R_FINITE(angle))
1785
	errorcall(call, "invalid head angle");
1815
	errorcall(call, "invalid head angle");
1786
    args = CDR(args);
1816
    args = CDR(args);
1787
 
1817
 
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);
1799
    args = CDR(args);
1834
    args = CDR(args);
1800
 
1835
 
1801
    PROTECT(lwd = CAR(args));/*need  FixupLwd ?*/
1836
    PROTECT(lwd = CAR(args));/*need  FixupLwd ?*/
1802
    nlwd = length(lwd);
1837
    nlwd = length(lwd);
1803
    if (nlwd == 0)
1838
    if (nlwd == 0)
1804
	errorcall(call, "'lwd' must be numeric of length >=1");
1839
	errorcall(call, "'lwd' must be numeric of length >=1");
1805
    args = CDR(args);
1840
    args = CDR(args);
1806
 
1841
 
1807
    sxpd = CAR(args);
1842
    sxpd = CAR(args);
1808
    if (sxpd != R_NilValue)
1843
    if (sxpd != R_NilValue)
1809
	xpd = asInteger(sxpd);
1844
	xpd = asInteger(sxpd);
1810
    else
1845
    else
1811
	xpd = Rf_gpptr(dd)->xpd;
1846
	xpd = Rf_gpptr(dd)->xpd;
1812
    args = CDR(args);
1847
    args = CDR(args);
1813
 
1848
 
1814
    GSavePars(dd);
1849
    GSavePars(dd);
1815
 
1850
 
1816
    if (xpd == NA_INTEGER)
1851
    if (xpd == NA_INTEGER)
1817
	Rf_gpptr(dd)->xpd = 2;
1852
	Rf_gpptr(dd)->xpd = 2;
1818
    else
1853
    else
1819
	Rf_gpptr(dd)->xpd = xpd;
1854
	Rf_gpptr(dd)->xpd = xpd;
1820
 
1855
 
1821
    x0 = REAL(sx0);
1856
    x0 = REAL(sx0);
1822
    y0 = REAL(sy0);
1857
    y0 = REAL(sy0);
1823
    x1 = REAL(sx1);
1858
    x1 = REAL(sx1);
1824
    y1 = REAL(sy1);
1859
    y1 = REAL(sy1);
1825
 
1860
 
1826
    GMode(1, dd);
1861
    GMode(1, dd);
1827
    for (i = 0; i < n; i++) {
1862
    for (i = 0; i < n; i++) {
1828
	xx0 = x0[i%nx0];
1863
	xx0 = x0[i%nx0];
1829
	yy0 = y0[i%ny0];
1864
	yy0 = y0[i%ny0];
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];
1843
	    GArrow(xx0, yy0, xx1, yy1, DEVICE,
1879
	    GArrow(xx0, yy0, xx1, yy1, DEVICE,
1844
		   hlength, angle, code, dd);
1880
		   hlength, angle, code, dd);
1845
	}
1881
	}
1846
    }
1882
    }
1847
    GMode(0, dd);
1883
    GMode(0, dd);
1848
    GRestorePars(dd);
1884
    GRestorePars(dd);
1849
 
1885
 
1850
    UNPROTECT(3);
1886
    UNPROTECT(3);
1851
    /* NOTE: only record operation if no "error"  */
1887
    /* NOTE: only record operation if no "error"  */
1852
    if (GRecording(call))
1888
    if (GRecording(call))
1853
	recordGraphicOperation(op, originalArgs, dd);
1889
	recordGraphicOperation(op, originalArgs, dd);
1854
    return R_NilValue;
1890
    return R_NilValue;
1855
}
1891
}
1856
 
1892
 
1857
 
1893
 
1858
static void drawPolygon(int n, double *x, double *y,
1894
static void drawPolygon(int n, double *x, double *y,
1859
			int lty, int fill, int border, DevDesc *dd)
1895
			int lty, int fill, int border, DevDesc *dd)
1860
{
1896
{
1861
    if (lty == NA_INTEGER)
1897
    if (lty == NA_INTEGER)
1862
	Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
1898
	Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
1863
    else
1899
    else
1864
	Rf_gpptr(dd)->lty = lty;
1900
	Rf_gpptr(dd)->lty = lty;
1865
    GPolygon(n, x, y, USER, fill, border, dd);
1901
    GPolygon(n, x, y, USER, fill, border, dd);
1866
}
1902
}
1867
 
1903
 
1868
SEXP do_polygon(SEXP call, SEXP op, SEXP args, SEXP env)
1904
SEXP do_polygon(SEXP call, SEXP op, SEXP args, SEXP env)
1869
{
1905
{
1870
    /* polygon(x, y, col, border, lty, xpd, ...) */
1906
    /* polygon(x, y, col, border, lty, xpd, ...) */
1871
    SEXP sx, sy, col, border, lty, sxpd;
1907
    SEXP sx, sy, col, border, lty, sxpd;
1872
    int nx;
1908
    int nx;
1873
    int ncol, nborder, nlty, xpd, i, start=0;
1909
    int ncol, nborder, nlty, xpd, i, start=0;
1874
    int num = 0;
1910
    int num = 0;
1875
    double *x, *y, xx, yy, xold, yold;
1911
    double *x, *y, xx, yy, xold, yold;
1876
 
1912
 
1877
    SEXP originalArgs = args;
1913
    SEXP originalArgs = args;
1878
    DevDesc *dd = CurrentDevice();
1914
    DevDesc *dd = CurrentDevice();
1879
 
1915
 
1880
    GCheckState(dd);
1916
    GCheckState(dd);
1881
 
1917
 
1882
    if (length(args) < 2) errorcall(call, "too few arguments");
1918
    if (length(args) < 2) errorcall(call, "too few arguments");
1883
    /* (x,y) is checked in R via xy.coords() ; no need here : */
1919
    /* (x,y) is checked in R via xy.coords() ; no need here : */
1884
    sx = SETCAR(args, coerceVector(CAR(args), REALSXP));  args = CDR(args);
1920
    sx = SETCAR(args, coerceVector(CAR(args), REALSXP));  args = CDR(args);
1885
    sy = SETCAR(args, coerceVector(CAR(args), REALSXP));  args = CDR(args);
1921
    sy = SETCAR(args, coerceVector(CAR(args), REALSXP));  args = CDR(args);
1886
    nx = LENGTH(sx);
1922
    nx = LENGTH(sx);
1887
 
1923
 
1888
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));	args = CDR(args);
1924
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));	args = CDR(args);
1889
    ncol = LENGTH(col);
1925
    ncol = LENGTH(col);
1890
 
1926
 
1891
    PROTECT(border = FixupCol(CAR(args), Rf_gpptr(dd)->fg));	args = CDR(args);
1927
    PROTECT(border = FixupCol(CAR(args), Rf_gpptr(dd)->fg));	args = CDR(args);
1892
    nborder = LENGTH(border);
1928
    nborder = LENGTH(border);
1893
 
1929
 
1894
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));	args = CDR(args);
1930
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));	args = CDR(args);
1895
    nlty = length(lty);
1931
    nlty = length(lty);
1896
 
1932
 
1897
    sxpd = CAR(args);
1933
    sxpd = CAR(args);
1898
    if (sxpd != R_NilValue)
1934
    if (sxpd != R_NilValue)
1899
	xpd = asInteger(sxpd);
1935
	xpd = asInteger(sxpd);
1900
    else
1936
    else
1901
	xpd = Rf_gpptr(dd)->xpd;
1937
	xpd = Rf_gpptr(dd)->xpd;
1902
    args = CDR(args);
1938
    args = CDR(args);
1903
 
1939
 
1904
    GSavePars(dd);
1940
    GSavePars(dd);
1905
    ProcessInlinePars(args, dd, call);
1941
    ProcessInlinePars(args, dd, call);
1906
 
1942
 
1907
    if (xpd == NA_INTEGER)
1943
    if (xpd == NA_INTEGER)
1908
	Rf_gpptr(dd)->xpd = 2;
1944
	Rf_gpptr(dd)->xpd = 2;
1909
    else
1945
    else
1910
	Rf_gpptr(dd)->xpd = xpd;
1946
	Rf_gpptr(dd)->xpd = xpd;
1911
 
1947
 
1912
    GMode(1, dd);
1948
    GMode(1, dd);
1913
 
1949
 
1914
    x = REAL(sx);
1950
    x = REAL(sx);
1915
    y = REAL(sy);
1951
    y = REAL(sy);
1916
    xold = NA_REAL;
1952
    xold = NA_REAL;
1917
    yold = NA_REAL;
1953
    yold = NA_REAL;
1918
    for (i = 0; i < nx; i++) {
1954
    for (i = 0; i < nx; i++) {
1919
	xx = x[i];
1955
	xx = x[i];
1920
	yy = y[i];
1956
	yy = y[i];
1921
	GConvert(&xx, &yy, USER, DEVICE, dd);
1957
	GConvert(&xx, &yy, USER, DEVICE, dd);
1922
	if ((R_FINITE(xx) && R_FINITE(yy)) &&
1958
	if ((R_FINITE(xx) && R_FINITE(yy)) &&
1923
	    !(R_FINITE(xold) && R_FINITE(yold)))
1959
	    !(R_FINITE(xold) && R_FINITE(yold)))
1924
	    start = i; /* first point of current segment */
1960
	    start = i; /* first point of current segment */
1925
	else if ((R_FINITE(xold) && R_FINITE(yold)) &&
1961
	else if ((R_FINITE(xold) && R_FINITE(yold)) &&
1926
		 !(R_FINITE(xx) && R_FINITE(yy))) {
1962
		 !(R_FINITE(xx) && R_FINITE(yy))) {
1927
	    if (i-start > 1) {
1963
	    if (i-start > 1) {
1928
		drawPolygon(i-start, x+start, y+start,
1964
		drawPolygon(i-start, x+start, y+start,
1929
			    INTEGER(lty)[num%nlty],
1965
			    INTEGER(lty)[num%nlty],
1930
			    INTEGER(col)[num%ncol],
1966
			    INTEGER(col)[num%ncol],
1931
			    INTEGER(border)[num%nborder], dd);
1967
			    INTEGER(border)[num%nborder], dd);
1932
		num++;
1968
		num++;
1933
	    }
1969
	    }
1934
	}
1970
	}
1935
	else if ((R_FINITE(xold) && R_FINITE(yold)) && (i == nx-1)) { /* last */
1971
	else if ((R_FINITE(xold) && R_FINITE(yold)) && (i == nx-1)) { /* last */
1936
	    drawPolygon(nx-start, x+start, y+start,
1972
	    drawPolygon(nx-start, x+start, y+start,
1937
			INTEGER(lty)[num%nlty],
1973
			INTEGER(lty)[num%nlty],
1938
			INTEGER(col)[num%ncol],
1974
			INTEGER(col)[num%ncol],
1939
			INTEGER(border)[num%nborder], dd);
1975
			INTEGER(border)[num%nborder], dd);
1940
	    num++;
1976
	    num++;
1941
	}
1977
	}
1942
	xold = xx;
1978
	xold = xx;
1943
	yold = yy;
1979
	yold = yy;
1944
    }
1980
    }
1945
 
1981
 
1946
    GMode(0, dd);
1982
    GMode(0, dd);
1947
 
1983
 
1948
    GRestorePars(dd);
1984
    GRestorePars(dd);
1949
    UNPROTECT(3);
1985
    UNPROTECT(3);
1950
    /* NOTE: only record operation if no "error"  */
1986
    /* NOTE: only record operation if no "error"  */
1951
    if (GRecording(call))
1987
    if (GRecording(call))
1952
	recordGraphicOperation(op, originalArgs, dd);
1988
	recordGraphicOperation(op, originalArgs, dd);
1953
    return R_NilValue;
1989
    return R_NilValue;
1954
}
1990
}
1955
 
1991
 
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;
1967
    SEXP string, originalArgs = args;
2003
    SEXP string, originalArgs = args;
1968
    DevDesc *dd = CurrentDevice();
2004
    DevDesc *dd = CurrentDevice();
1969
 
2005
 
1970
    GCheckState(dd);
2006
    GCheckState(dd);
1971
 
2007
 
1972
    if (length(args) < 3) errorcall(call, "too few arguments");
2008
    if (length(args) < 3) errorcall(call, "too few arguments");
1973
 
2009
 
1974
    PLOT_XY_DEALING("text");
2010
    PLOT_XY_DEALING("text");
1975
 
2011
 
1976
    /* labels */
2012
    /* labels */
1977
    txt = CAR(args);
2013
    txt = CAR(args);
1978
    if (isSymbol(txt) || isLanguage(txt))
2014
    if (isSymbol(txt) || isLanguage(txt))
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;
1990
	adjy = NA_REAL;
2026
	adjy = NA_REAL;
1991
    }
2027
    }
1992
    else if (isReal(adj)) {
2028
    else if (isReal(adj)) {
1993
	if (LENGTH(adj) == 1) {
2029
	if (LENGTH(adj) == 1) {
1994
	    adjx = REAL(adj)[0];
2030
	    adjx = REAL(adj)[0];
1995
	    adjy = NA_REAL;
2031
	    adjy = NA_REAL;
1996
	}
2032
	}
1997
	else {
2033
	else {
1998
	    adjx = REAL(adj)[0];
2034
	    adjx = REAL(adj)[0];
1999
	    adjy = REAL(adj)[1];
2035
	    adjy = REAL(adj)[1];
2000
	}
2036
	}
2001
    }
2037
    }
2002
    else if (isInteger(adj)) {
2038
    else if (isInteger(adj)) {
2003
	if (LENGTH(adj) == 1) {
2039
	if (LENGTH(adj) == 1) {
2004
	    adjx = INTEGER(adj)[0];
2040
	    adjx = INTEGER(adj)[0];
2005
	    adjy = NA_REAL;
2041
	    adjy = NA_REAL;
2006
	}
2042
	}
2007
	else {
2043
	else {
2008
	    adjx = INTEGER(adj)[0];
2044
	    adjx = INTEGER(adj)[0];
2009
	    adjy = INTEGER(adj)[1];
2045
	    adjy = INTEGER(adj)[1];
2010
	}
2046
	}
2011
    }
2047
    }
2012
    else errorcall(call, "invalid adj value");
2048
    else errorcall(call, "invalid adj value");
2013
    args = CDR(args);
2049
    args = CDR(args);
2014
 
2050
 
2015
    PROTECT(pos = coerceVector(CAR(args), INTSXP));
2051
    PROTECT(pos = coerceVector(CAR(args), INTSXP));
2016
    npos = length(pos);
2052
    npos = length(pos);
2017
    for (i = 0; i < npos; i++)
2053
    for (i = 0; i < npos; i++)
2018
	if (INTEGER(pos)[i] < 1 || INTEGER(pos)[i] > 4)
2054
	if (INTEGER(pos)[i] < 1 || INTEGER(pos)[i] > 4)
2019
	    errorcall(call, "invalid pos value");
2055
	    errorcall(call, "invalid pos value");
2020
    args = CDR(args);
2056
    args = CDR(args);
2021
 
2057
 
2022
    offset = GConvertXUnits(asReal(CAR(args)), CHARS, INCHES, dd);
2058
    offset = GConvertXUnits(asReal(CAR(args)), CHARS, INCHES, dd);
2023
    args = CDR(args);
2059
    args = CDR(args);
2024
 
2060
 
2025
    PROTECT(vfont = FixupVFont(CAR(args)));
2061
    PROTECT(vfont = FixupVFont(CAR(args)));
2026
    if (!isNull(vfont))
2062
    if (!isNull(vfont))
2027
	vectorFonts = TRUE;
2063
	vectorFonts = TRUE;
2028
    args = CDR(args);
2064
    args = CDR(args);
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);
2040
    args = CDR(args);
2077
    args = CDR(args);
2041
 
2078
 
2042
    sxpd = CAR(args); /* xpd: NULL -> par("xpd") */
2079
    sxpd = CAR(args); /* xpd: NULL -> par("xpd") */
2043
    if (sxpd != R_NilValue)
2080
    if (sxpd != R_NilValue)
2044
	xpd = asInteger(sxpd);
2081
	xpd = asInteger(sxpd);
2045
    else
2082
    else
2046
	xpd = Rf_gpptr(dd)->xpd;
2083
	xpd = Rf_gpptr(dd)->xpd;
2047
    args = CDR(args);
2084
    args = CDR(args);
2048
 
2085
 
2049
    x = REAL(sx);
2086
    x = REAL(sx);
2050
    y = REAL(sy);
2087
    y = REAL(sy);
2051
    n = LENGTH(sx);
2088
    n = LENGTH(sx);
2052
    ntxt = LENGTH(txt);
2089
    ntxt = LENGTH(txt);
2053
 
2090
 
2054
    GSavePars(dd);
2091
    GSavePars(dd);
2055
    ProcessInlinePars(args, dd, call);
2092
    ProcessInlinePars(args, dd, call);
2056
 
2093
 
2057
    Rf_gpptr(dd)->xpd = (xpd == NA_INTEGER)? 2 : xpd;
2094
    Rf_gpptr(dd)->xpd = (xpd == NA_INTEGER)? 2 : xpd;
2058
 
2095
 
2059
    GMode(1, dd);
2096
    GMode(1, dd);
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];
2071
	    else
2108
	    else
2072
		Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase;
2109
		Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase;
2073
	    if (nfont && INTEGER(font)[i % nfont] != NA_INTEGER)
2110
	    if (nfont && INTEGER(font)[i % nfont] != NA_INTEGER)
2074
		Rf_gpptr(dd)->font = INTEGER(font)[i % nfont];
2111
		Rf_gpptr(dd)->font = INTEGER(font)[i % nfont];
2075
	    else
2112
	    else
2076
		Rf_gpptr(dd)->font = Rf_dpptr(dd)->font;
2113
		Rf_gpptr(dd)->font = Rf_dpptr(dd)->font;
2077
	    if (npos > 0) {
2114
	    if (npos > 0) {
2078
		switch(INTEGER(pos)[i % npos]) {
2115
		switch(INTEGER(pos)[i % npos]) {
2079
		case 1:
2116
		case 1:
2080
		    yy = yy - offset;
2117
		    yy = yy - offset;
2081
		    adjx = 0.5;
2118
		    adjx = 0.5;
2082
		    adjy = 1 - (0.5 - Rf_gpptr(dd)->yCharOffset);
2119
		    adjy = 1 - (0.5 - Rf_gpptr(dd)->yCharOffset);
2083
		    break;
2120
		    break;
2084
		case 2:
2121
		case 2:
2085
		    xx = xx - offset;
2122
		    xx = xx - offset;
2086
		    adjx = 1;
2123
		    adjx = 1;
2087
		    adjy = Rf_gpptr(dd)->yCharOffset;
2124
		    adjy = Rf_gpptr(dd)->yCharOffset;
2088
		    break;
2125
		    break;
2089
		case 3:
2126
		case 3:
2090
		    yy = yy + offset;
2127
		    yy = yy + offset;
2091
		    adjx = 0.5;
2128
		    adjx = 0.5;
2092
		    adjy = 0;
2129
		    adjy = 0;
2093
		    break;
2130
		    break;
2094
		case 4:
2131
		case 4:
2095
		    xx = xx + offset;
2132
		    xx = xx + offset;
2096
		    adjx = 0;
2133
		    adjx = 0;
2097
		    adjy = Rf_gpptr(dd)->yCharOffset;
2134
		    adjy = Rf_gpptr(dd)->yCharOffset;
2098
		    break;
2135
		    break;
2099
		}
2136
		}
2100
	    }
2137
	    }
2101
	    if (vectorFonts) {
2138
	    if (vectorFonts) {
2102
		string = STRING_ELT(txt, i % ntxt);
2139
		string = STRING_ELT(txt, i % ntxt);
2103
		if(string != NA_STRING)
2140
		if(string != NA_STRING)
2104
		    GVText(xx, yy, INCHES, CHAR(string),
2141
		    GVText(xx, yy, INCHES, CHAR(string),
2105
			   INTEGER(vfont)[0], INTEGER(vfont)[1],
2142
			   INTEGER(vfont)[0], INTEGER(vfont)[1],
2106
			   adjx, adjy, Rf_gpptr(dd)->srt, dd);
2143
			   adjx, adjy, Rf_gpptr(dd)->srt, dd);
2107
	    } else if (isExpression(txt)) {
2144
	    } else if (isExpression(txt)) {
2108
		GMathText(xx, yy, INCHES, VECTOR_ELT(txt, i % ntxt),
2145
		GMathText(xx, yy, INCHES, VECTOR_ELT(txt, i % ntxt),
2109
			  adjx, adjy, Rf_gpptr(dd)->srt, dd);
2146
			  adjx, adjy, Rf_gpptr(dd)->srt, dd);
2110
	    } else {
2147
	    } else {
2111
		string = STRING_ELT(txt, i % ntxt);
2148
		string = STRING_ELT(txt, i % ntxt);
2112
		if(string != NA_STRING)
2149
		if(string != NA_STRING)
2113
		    GText(xx, yy, INCHES, CHAR(string),
2150
		    GText(xx, yy, INCHES, CHAR(string),
2114
			  adjx, adjy, Rf_gpptr(dd)->srt, dd);
2151
			  adjx, adjy, Rf_gpptr(dd)->srt, dd);
2115
	    }
2152
	    }
2116
	}
2153
	}
2117
    }
2154
    }
2118
    GMode(0, dd);
2155
    GMode(0, dd);
2119
 
2156
 
2120
    GRestorePars(dd);
2157
    GRestorePars(dd);
2121
    UNPROTECT(7);
2158
    UNPROTECT(7);
2122
    /* NOTE: only record operation if no "error"  */
2159
    /* NOTE: only record operation if no "error"  */
2123
    if (GRecording(call))
2160
    if (GRecording(call))
2124
	recordGraphicOperation(op, originalArgs, dd);
2161
	recordGraphicOperation(op, originalArgs, dd);
2125
    return R_NilValue;
2162
    return R_NilValue;
2126
}
2163
}
2127
 
2164
 
2128
static double ComputeAdjValue(double adj, int side, int las)
2165
static double ComputeAdjValue(double adj, int side, int las)
2129
{
2166
{
2130
    if (!R_FINITE(adj)) {
2167
    if (!R_FINITE(adj)) {
2131
	switch(las) {
2168
	switch(las) {
2132
	case 0:/* parallel to axis */
2169
	case 0:/* parallel to axis */
2133
	    adj = 0.5; break;
2170
	    adj = 0.5; break;
2134
	case 1:/* horizontal */
2171
	case 1:/* horizontal */
2135
	    switch(side) {
2172
	    switch(side) {
2136
	    case 1:
2173
	    case 1:
2137
	    case 3: adj = 0.5; break;
2174
	    case 3: adj = 0.5; break;
2138
	    case 2: adj = 1.0; break;
2175
	    case 2: adj = 1.0; break;
2139
	    case 4: adj = 0.0; break;
2176
	    case 4: adj = 0.0; break;
2140
	    }
2177
	    }
2141
	    break;
2178
	    break;
2142
	case 2:/* perpendicular to axis */
2179
	case 2:/* perpendicular to axis */
2143
	    switch(side) {
2180
	    switch(side) {
2144
	    case 1:
2181
	    case 1:
2145
	    case 2: adj = 1.0; break;
2182
	    case 2: adj = 1.0; break;
2146
	    case 3:
2183
	    case 3:
2147
	    case 4: adj = 0.0; break;
2184
	    case 4: adj = 0.0; break;
2148
	    }
2185
	    }
2149
	    break;
2186
	    break;
2150
	case 3:/* vertical */
2187
	case 3:/* vertical */
2151
	    switch(side) {
2188
	    switch(side) {
2152
	    case 1: adj = 1.0; break;
2189
	    case 1: adj = 1.0; break;
2153
	    case 3: adj = 0.0; break;
2190
	    case 3: adj = 0.0; break;
2154
	    case 2:
2191
	    case 2:
2155
	    case 4: adj = 0.5; break;
2192
	    case 4: adj = 0.5; break;
2156
	    }
2193
	    }
2157
	    break;
2194
	    break;
2158
	}
2195
	}
2159
    }
2196
    }
2160
    return adj;
2197
    return adj;
2161
}
2198
}
2162
 
2199
 
2163
static double ComputeAtValueFromAdj(double adj, int side, int outer,
2200
static double ComputeAtValueFromAdj(double adj, int side, int outer,
2164
				    DevDesc *dd)
2201
				    DevDesc *dd)
2165
{
2202
{
2166
    double at = 0;		/* -Wall */
2203
    double at = 0;		/* -Wall */
2167
    switch(side % 2) {
2204
    switch(side % 2) {
2168
    case 0:
2205
    case 0:
2169
	at  = outer ? adj : yNPCtoUsr(adj, dd);
2206
	at  = outer ? adj : yNPCtoUsr(adj, dd);
2170
	break;
2207
	break;
2171
    case 1:
2208
    case 1:
2172
	at = outer ? adj : xNPCtoUsr(adj, dd);
2209
	at = outer ? adj : xNPCtoUsr(adj, dd);
2173
	break;
2210
	break;
2174
    }
2211
    }
2175
    return at;
2212
    return at;
2176
}
2213
}
2177
 
2214
 
2178
static double ComputeAtValue(double at, double adj,
2215
static double ComputeAtValue(double at, double adj,
2179
			     int side, int las, int outer,
2216
			     int side, int las, int outer,
2180
			     DevDesc *dd)
2217
			     DevDesc *dd)
2181
{
2218
{
2182
    if (!R_FINITE(at)) {
2219
    if (!R_FINITE(at)) {
2183
	/* If the text is parallel to the axis, use "adj" for "at"
2220
	/* If the text is parallel to the axis, use "adj" for "at"
2184
	 * Otherwise, centre the text
2221
	 * Otherwise, centre the text
2185
	 */
2222
	 */
2186
	switch(las) {
2223
	switch(las) {
2187
	case 0:/* parallel to axis */
2224
	case 0:/* parallel to axis */
2188
	    at = ComputeAtValueFromAdj(adj, side, outer, dd);
2225
	    at = ComputeAtValueFromAdj(adj, side, outer, dd);
2189
	    break;
2226
	    break;
2190
	case 1:/* horizontal */
2227
	case 1:/* horizontal */
2191
	    switch(side) {
2228
	    switch(side) {
2192
	    case 1:
2229
	    case 1:
2193
	    case 3:
2230
	    case 3:
2194
		at = ComputeAtValueFromAdj(adj, side, outer, dd);
2231
		at = ComputeAtValueFromAdj(adj, side, outer, dd);
2195
		break;
2232
		break;
2196
	    case 2:
2233
	    case 2:
2197
	    case 4:
2234
	    case 4:
2198
		at = outer ? 0.5 : yNPCtoUsr(0.5, dd);
2235
		at = outer ? 0.5 : yNPCtoUsr(0.5, dd);
2199
		break;
2236
		break;
2200
	    }
2237
	    }
2201
	    break;
2238
	    break;
2202
	case 2:/* perpendicular to axis */
2239
	case 2:/* perpendicular to axis */
2203
	    switch(side) {
2240
	    switch(side) {
2204
	    case 1:
2241
	    case 1:
2205
	    case 3:
2242
	    case 3:
2206
		at = outer ? 0.5 : xNPCtoUsr(0.5, dd);
2243
		at = outer ? 0.5 : xNPCtoUsr(0.5, dd);
2207
		break;
2244
		break;
2208
	    case 2:
2245
	    case 2:
2209
	    case 4:
2246
	    case 4:
2210
		at = outer ? 0.5 : yNPCtoUsr(0.5, dd);
2247
		at = outer ? 0.5 : yNPCtoUsr(0.5, dd);
2211
		break;
2248
		break;
2212
	    }
2249
	    }
2213
	    break;
2250
	    break;
2214
	case 3:/* vertical */
2251
	case 3:/* vertical */
2215
	    switch(side) {
2252
	    switch(side) {
2216
	    case 1:
2253
	    case 1:
2217
	    case 3:
2254
	    case 3:
2218
		at = outer ? 0.5 : xNPCtoUsr(0.5, dd);
2255
		at = outer ? 0.5 : xNPCtoUsr(0.5, dd);
2219
		break;
2256
		break;
2220
	    case 2:
2257
	    case 2:
2221
	    case 4:
2258
	    case 4:
2222
		at = ComputeAtValueFromAdj(adj, side, outer, dd);
2259
		at = ComputeAtValueFromAdj(adj, side, outer, dd);
2223
		break;
2260
		break;
2224
	    }
2261
	    }
2225
	    break;
2262
	    break;
2226
	}
2263
	}
2227
    }
2264
    }
2228
    return at;
2265
    return at;
2229
}
2266
}
2230
 
2267
 
2231
/* mtext(text,
2268
/* mtext(text,
2232
	 side = 3,
2269
	 side = 3,
2233
	 line = 0,
2270
	 line = 0,
2234
	 outer = TRUE,
2271
	 outer = TRUE,
2235
	 at = NA,
2272
	 at = NA,
2236
	 adj = NA,
2273
	 adj = NA,
2237
	 cex = NA,
2274
	 cex = NA,
2238
	 col = NA,
2275
	 col = NA,
2239
	 font = NA,
2276
	 font = NA,
2240
	 vfont = NULL,
2277
	 vfont = NULL,
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;
2251
    SEXP originalArgs = args;
2289
    SEXP originalArgs = args;
2252
    DevDesc *dd = CurrentDevice();
2290
    DevDesc *dd = CurrentDevice();
2253
 
2291
 
2254
    GCheckState(dd);
2292
    GCheckState(dd);
2255
 
2293
 
2256
    if (length(args) < 9)
2294
    if (length(args) < 9)
2257
	errorcall(call, "too few arguments");
2295
	errorcall(call, "too few arguments");
2258
 
2296
 
2259
    /* Arg1 : text= */
2297
    /* Arg1 : text= */
2260
    text = CAR(args);
2298
    text = CAR(args);
2261
    if (isSymbol(text) || isLanguage(text))
2299
    if (isSymbol(text) || isLanguage(text))
2262
	text = coerceVector(text, EXPRSXP);
2300
	text = coerceVector(text, EXPRSXP);
2263
    else if (!isExpression(text))
2301
    else if (!isExpression(text))
2264
	text = coerceVector(text, STRSXP);
2302
	text = coerceVector(text, STRSXP);
2265
    PROTECT(text);
2303
    PROTECT(text);
2266
    n = ntext = length(text);
2304
    n = ntext = length(text);
2267
    if (ntext <= 0)
2305
    if (ntext <= 0)
2268
	errorcall(call, "zero length \"text\" specified");
2306
	errorcall(call, "zero length \"text\" specified");
2269
    args = CDR(args);
2307
    args = CDR(args);
2270
 
2308
 
2271
    /* Arg2 : side= */
2309
    /* Arg2 : side= */
2272
    PROTECT(side = coerceVector(CAR(args), INTSXP));
2310
    PROTECT(side = coerceVector(CAR(args), INTSXP));
2273
    nside = length(side);
2311
    nside = length(side);
2274
    if (nside <= 0) errorcall(call, "zero length \"side\" specified");
2312
    if (nside <= 0) errorcall(call, "zero length \"side\" specified");
2275
    if (n < nside) n = nside;
2313
    if (n < nside) n = nside;
2276
    args = CDR(args);
2314
    args = CDR(args);
2277
 
2315
 
2278
    /* Arg3 : line= */
2316
    /* Arg3 : line= */
2279
    PROTECT(line = coerceVector(CAR(args), REALSXP));
2317
    PROTECT(line = coerceVector(CAR(args), REALSXP));
2280
    nline = length(line);
2318
    nline = length(line);
2281
    if (nline <= 0) errorcall(call, "zero length \"line\" specified");
2319
    if (nline <= 0) errorcall(call, "zero length \"line\" specified");
2282
    if (n < nline) n = nline;
2320
    if (n < nline) n = nline;
2283
    args = CDR(args);
2321
    args = CDR(args);
2284
 
2322
 
2285
    /* Arg4 : outer= */
2323
    /* Arg4 : outer= */
2286
    /* outer == NA => outer <- 0 */
2324
    /* outer == NA => outer <- 0 */
2287
    PROTECT(outer = coerceVector(CAR(args), INTSXP));
2325
    PROTECT(outer = coerceVector(CAR(args), INTSXP));
2288
    nouter = length(outer);
2326
    nouter = length(outer);
2289
    if (nouter <= 0) errorcall(call, "zero length \"outer\" specified");
2327
    if (nouter <= 0) errorcall(call, "zero length \"outer\" specified");
2290
    if (n < nouter) n = nouter;
2328
    if (n < nouter) n = nouter;
2291
    args = CDR(args);
2329
    args = CDR(args);
2292
 
2330
 
2293
    /* Arg5 : at= */
2331
    /* Arg5 : at= */
2294
    PROTECT(at = coerceVector(CAR(args), REALSXP));
2332
    PROTECT(at = coerceVector(CAR(args), REALSXP));
2295
    nat = length(at);
2333
    nat = length(at);
2296
    if (nat <= 0) errorcall(call, "zero length \"at\" specified");
2334
    if (nat <= 0) errorcall(call, "zero length \"at\" specified");
2297
    if (n < nat) n = nat;
2335
    if (n < nat) n = nat;
2298
    args = CDR(args);
2336
    args = CDR(args);
2299
 
2337
 
2300
    /* Arg6 : adj= */
2338
    /* Arg6 : adj= */
2301
    PROTECT(adj = coerceVector(CAR(args), REALSXP));
2339
    PROTECT(adj = coerceVector(CAR(args), REALSXP));
2302
    nadj = length(adj);
2340
    nadj = length(adj);
2303
    if (nadj <= 0) errorcall(call, "zero length \"adj\" specified");
2341
    if (nadj <= 0) errorcall(call, "zero length \"adj\" specified");
2304
    if (n < nadj) n = nadj;
2342
    if (n < nadj) n = nadj;
2305
    args = CDR(args);
2343
    args = CDR(args);
2306
 
2344
 
2307
    /* Arg7 : cex */
2345
    /* Arg7 : cex */
2308
    PROTECT(cex = FixupCex(CAR(args), 1.0));
2346
    PROTECT(cex = FixupCex(CAR(args), 1.0));
2309
    ncex = length(cex);
2347
    ncex = length(cex);
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
 
2321
    /* Arg9 : font */
2360
    /* Arg9 : font */
2322
    PROTECT(font = FixupFont(CAR(args), NA_INTEGER));
2361
    PROTECT(font = FixupFont(CAR(args), NA_INTEGER));
2323
    nfont = length(font);
2362
    nfont = length(font);
2324
    if (nfont <= 0) errorcall(call, "zero length \"font\" specified");
2363
    if (nfont <= 0) errorcall(call, "zero length \"font\" specified");
2325
    if (n < nfont) n = nfont;
2364
    if (n < nfont) n = nfont;
2326
    args = CDR(args);
2365
    args = CDR(args);
2327
 
2366
 
2328
    /* Arg10 : vfont */
2367
    /* Arg10 : vfont */
2329
    PROTECT(vfont = FixupVFont(CAR(args)));
2368
    PROTECT(vfont = FixupVFont(CAR(args)));
2330
    if (!isNull(vfont))
2369
    if (!isNull(vfont))
2331
	vectorFonts = TRUE;
2370
	vectorFonts = TRUE;
2332
    args = CDR(args);
2371
    args = CDR(args);
2333
 
2372
 
2334
    GSavePars(dd);
2373
    GSavePars(dd);
2335
    ProcessInlinePars(args, dd, call);
2374
    ProcessInlinePars(args, dd, call);
2336
 
2375
 
2337
    /* If we only scribble in the outer margins, */
2376
    /* If we only scribble in the outer margins, */
2338
    /* we don't want to mark the plot as dirty. */
2377
    /* we don't want to mark the plot as dirty. */
2339
 
2378
 
2340
    dirtyplot = FALSE;
2379
    dirtyplot = FALSE;
2341
    gpnewsave = Rf_gpptr(dd)->new;
2380
    gpnewsave = Rf_gpptr(dd)->new;
2342
    dpnewsave = Rf_dpptr(dd)->new;
2381
    dpnewsave = Rf_dpptr(dd)->new;
2343
    cexsave = Rf_gpptr(dd)->cex;
2382
    cexsave = Rf_gpptr(dd)->cex;
2344
    fontsave = Rf_gpptr(dd)->font;
2383
    fontsave = Rf_gpptr(dd)->font;
2345
    colsave = Rf_gpptr(dd)->col;
2384
    colsave = Rf_gpptr(dd)->col;
2346
 
2385
 
2347
    /* override par("xpd") and force clipping to figure region */
2386
    /* override par("xpd") and force clipping to figure region */
2348
    /* NOTE: don't override to _reduce_ clipping region */
2387
    /* NOTE: don't override to _reduce_ clipping region */
2349
    if (Rf_gpptr(dd)->xpd < 1)
2388
    if (Rf_gpptr(dd)->xpd < 1)
2350
	Rf_gpptr(dd)->xpd = 1;
2389
	Rf_gpptr(dd)->xpd = 1;
2351
 
2390
 
2352
    if (outer) {
2391
    if (outer) {
2353
	gpnewsave = Rf_gpptr(dd)->new;
2392
	gpnewsave = Rf_gpptr(dd)->new;
2354
	dpnewsave = Rf_dpptr(dd)->new;
2393
	dpnewsave = Rf_dpptr(dd)->new;
2355
	/* override par("xpd") and force clipping to device region */
2394
	/* override par("xpd") and force clipping to device region */
2356
	Rf_gpptr(dd)->xpd = 2;
2395
	Rf_gpptr(dd)->xpd = 2;
2357
    }
2396
    }
2358
    GMode(1, dd);
2397
    GMode(1, dd);
2359
 
2398
 
2360
    for (i = 0; i < n; i++) {
2399
    for (i = 0; i < n; i++) {
2361
	double atval = REAL(at)[i%nat];
2400
	double atval = REAL(at)[i%nat];
2362
	double adjval = REAL(adj)[i%nadj];
2401
	double adjval = REAL(adj)[i%nadj];
2363
	double cexval = REAL(cex)[i%ncex];
2402
	double cexval = REAL(cex)[i%ncex];
2364
	double lineval = REAL(line)[i%nline];
2403
	double lineval = REAL(line)[i%nline];
2365
	int outerval = INTEGER(outer)[i%nouter];
2404
	int outerval = INTEGER(outer)[i%nouter];
2366
	int sideval = INTEGER(side)[i%nside];
2405
	int sideval = INTEGER(side)[i%nside];
2367
	int fontval = INTEGER(font)[i%nfont];
2406
	int fontval = INTEGER(font)[i%nfont];
2368
	int colval = INTEGER(col)[i%ncol];
2407
	int colval = INTEGER(col)[i%ncol];
2369
 
2408
 
2370
	if (outerval == NA_INTEGER) outerval = 0;
2409
	if (outerval == NA_INTEGER) outerval = 0;
2371
	/* Note : we ignore any shrinking produced */
2410
	/* Note : we ignore any shrinking produced */
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) {
2383
	    string = STRING_ELT(text, i%ntext);
2425
	    string = STRING_ELT(text, i%ntext);
2384
#ifdef GMV_implemented
2426
#ifdef GMV_implemented
2385
	    if(string != NA_STRING)
2427
	    if(string != NA_STRING)
2386
		GMVText(CHAR(string),
2428
		GMVText(CHAR(string),
2387
			INTEGER(vfont)[0], INTEGER(vfont)[1],
2429
			INTEGER(vfont)[0], INTEGER(vfont)[1],
2388
			sideval, lineval, outerval, atval,
2430
			sideval, lineval, outerval, atval,
2389
			Rf_gpptr(dd)->las, dd);
2431
			Rf_gpptr(dd)->las, dd);
2390
#else
2432
#else
2391
	    warningcall(call,"Hershey fonts not yet implemented for mtext()");
2433
	    warningcall(call,"Hershey fonts not yet implemented for mtext()");
2392
	    if(string != NA_STRING)
2434
	    if(string != NA_STRING)
2393
		GMtext(CHAR(string), sideval, lineval, outerval, atval,
2435
		GMtext(CHAR(string), sideval, lineval, outerval, atval,
2394
		       Rf_gpptr(dd)->las, dd);
2436
		       Rf_gpptr(dd)->las, dd);
2395
#endif
2437
#endif
2396
	}
2438
	}
2397
	else if (isExpression(text))
2439
	else if (isExpression(text))
2398
	    GMMathText(VECTOR_ELT(text, i%ntext),
2440
	    GMMathText(VECTOR_ELT(text, i%ntext),
2399
		       sideval, lineval, outerval, atval, Rf_gpptr(dd)->las, dd);
2441
		       sideval, lineval, outerval, atval, Rf_gpptr(dd)->las, dd);
2400
	else {
2442
	else {
2401
	    string = STRING_ELT(text, i%ntext);
2443
	    string = STRING_ELT(text, i%ntext);
2402
	    if(string != NA_STRING)
2444
	    if(string != NA_STRING)
2403
		GMtext(CHAR(string), sideval, lineval, outerval, atval,
2445
		GMtext(CHAR(string), sideval, lineval, outerval, atval,
2404
		       Rf_gpptr(dd)->las, dd);
2446
		       Rf_gpptr(dd)->las, dd);
2405
	}
2447
	}
2406
 
2448
 
2407
	if (outerval == 0) dirtyplot = TRUE;
2449
	if (outerval == 0) dirtyplot = TRUE;
2408
    }
2450
    }
2409
    GMode(0, dd);
2451
    GMode(0, dd);
2410
 
2452
 
2411
    GRestorePars(dd);
2453
    GRestorePars(dd);
2412
    if (!dirtyplot) {
2454
    if (!dirtyplot) {
2413
	Rf_gpptr(dd)->new = gpnewsave;
2455
	Rf_gpptr(dd)->new = gpnewsave;
2414
	Rf_dpptr(dd)->new = dpnewsave;
2456
	Rf_dpptr(dd)->new = dpnewsave;
2415
    }
2457
    }
2416
    UNPROTECT(10);
2458
    UNPROTECT(10);
2417
 
2459
 
2418
    /* NOTE: only record operation if no "error"  */
2460
    /* NOTE: only record operation if no "error"  */
2419
    if (GRecording(call))
2461
    if (GRecording(call))
2420
	recordGraphicOperation(op, originalArgs, dd);
2462
	recordGraphicOperation(op, originalArgs, dd);
2421
    return R_NilValue;
2463
    return R_NilValue;
2422
}/* do_mtext */
2464
}/* do_mtext */
2423
 
2465
 
2424
 
2466
 
2425
SEXP do_title(SEXP call, SEXP op, SEXP args, SEXP env)
2467
SEXP do_title(SEXP call, SEXP op, SEXP args, SEXP env)
2426
{
2468
{
2427
/* Annotation for plots :
2469
/* Annotation for plots :
2428
 
2470
 
2429
   title(main, sub, xlab, ylab,
2471
   title(main, sub, xlab, ylab,
2430
	 line, outer,
2472
	 line, outer,
2431
	 ...) */
2473
	 ...) */
2432
 
2474
 
2433
    SEXP Main, xlab, ylab, sub, vfont, string;
2475
    SEXP Main, xlab, ylab, sub, vfont, string;
2434
    double adj, adjy, cex, offset, line, hpos, vpos, where;
2476
    double adj, adjy, cex, offset, line, hpos, vpos, where;
2435
    int col, font, outer;
2477
    int col, font, outer;
2436
    int i, n;
2478
    int i, n;
2437
    SEXP originalArgs = args;
2479
    SEXP originalArgs = args;
2438
    DevDesc *dd = CurrentDevice();
2480
    DevDesc *dd = CurrentDevice();
2439
 
2481
 
2440
    GCheckState(dd);
2482
    GCheckState(dd);
2441
 
2483
 
2442
    if (length(args) < 6) errorcall(call, "too few arguments");
2484
    if (length(args) < 6) errorcall(call, "too few arguments");
2443
 
2485
 
2444
    Main = sub = xlab = ylab = R_NilValue;
2486
    Main = sub = xlab = ylab = R_NilValue;
2445
 
2487
 
2446
    if (CAR(args) != R_NilValue && LENGTH(CAR(args)) > 0)
2488
    if (CAR(args) != R_NilValue && LENGTH(CAR(args)) > 0)
2447
	Main = CAR(args);
2489
	Main = CAR(args);
2448
    args = CDR(args);
2490
    args = CDR(args);
2449
 
2491
 
2450
    if (CAR(args) != R_NilValue && LENGTH(CAR(args)) > 0)
2492
    if (CAR(args) != R_NilValue && LENGTH(CAR(args)) > 0)
2451
	sub = CAR(args);
2493
	sub = CAR(args);
2452
    args = CDR(args);
2494
    args = CDR(args);
2453
 
2495
 
2454
    if (CAR(args) != R_NilValue && LENGTH(CAR(args)) > 0)
2496
    if (CAR(args) != R_NilValue && LENGTH(CAR(args)) > 0)
2455
	xlab = CAR(args);
2497
	xlab = CAR(args);
2456
    args = CDR(args);
2498
    args = CDR(args);
2457
 
2499
 
2458
    if (CAR(args) != R_NilValue && LENGTH(CAR(args)) > 0)
2500
    if (CAR(args) != R_NilValue && LENGTH(CAR(args)) > 0)
2459
	ylab = CAR(args);
2501
	ylab = CAR(args);
2460
    args = CDR(args);
2502
    args = CDR(args);
2461
 
2503
 
2462
    line = asReal(CAR(args));
2504
    line = asReal(CAR(args));
2463
    args = CDR(args);
2505
    args = CDR(args);
2464
 
2506
 
2465
    outer = asLogical(CAR(args));
2507
    outer = asLogical(CAR(args));
2466
    if (outer == NA_LOGICAL) outer = 0;
2508
    if (outer == NA_LOGICAL) outer = 0;
2467
    args = CDR(args);
2509
    args = CDR(args);
2468
 
2510
 
2469
    GSavePars(dd);
2511
    GSavePars(dd);
2470
    ProcessInlinePars(args, dd, call);
2512
    ProcessInlinePars(args, dd, call);
2471
 
2513
 
2472
    /* override par("xpd") and force clipping to figure region */
2514
    /* override par("xpd") and force clipping to figure region */
2473
    /* NOTE: don't override to _reduce_ clipping region */
2515
    /* NOTE: don't override to _reduce_ clipping region */
2474
    if (Rf_gpptr(dd)->xpd < 1)
2516
    if (Rf_gpptr(dd)->xpd < 1)
2475
	Rf_gpptr(dd)->xpd = 1;
2517
	Rf_gpptr(dd)->xpd = 1;
2476
    if (outer)
2518
    if (outer)
2477
	Rf_gpptr(dd)->xpd = 2;
2519
	Rf_gpptr(dd)->xpd = 2;
2478
    adj = Rf_gpptr(dd)->adj;
2520
    adj = Rf_gpptr(dd)->adj;
2479
 
2521
 
2480
    GMode(1, dd);
2522
    GMode(1, dd);
2481
    if (Main != R_NilValue) {
2523
    if (Main != R_NilValue) {
2482
	cex = Rf_gpptr(dd)->cexmain;
2524
	cex = Rf_gpptr(dd)->cexmain;
2483
	col = Rf_gpptr(dd)->colmain;
2525
	col = Rf_gpptr(dd)->colmain;
2484
	font = Rf_gpptr(dd)->fontmain;
2526
	font = Rf_gpptr(dd)->fontmain;
2485
	GetTextArg(call, Main, &Main, &col, &cex, &font, &vfont);
2527
	GetTextArg(call, Main, &Main, &col, &cex, &font, &vfont);
2486
	Rf_gpptr(dd)->col = col;
2528
	Rf_gpptr(dd)->col = col;
2487
	Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * cex;
2529
	Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * cex;
2488
	Rf_gpptr(dd)->font = font;
2530
	Rf_gpptr(dd)->font = font;
2489
	if (outer) {
2531
	if (outer) {
2490
	    if (R_FINITE(line)) {
2532
	    if (R_FINITE(line)) {
2491
		vpos = line;
2533
		vpos = line;
2492
		adjy = 0;
2534
		adjy = 0;
2493
	    }
2535
	    }
2494
	    else {
2536
	    else {
2495
		vpos = 0.5 * Rf_gpptr(dd)->oma[2];
2537
		vpos = 0.5 * Rf_gpptr(dd)->oma[2];
2496
		adjy = 0.5;
2538
		adjy = 0.5;
2497
	    }
2539
	    }
2498
	    hpos = adj;
2540
	    hpos = adj;
2499
	    where = OMA3;
2541
	    where = OMA3;
2500
	}
2542
	}
2501
	else {
2543
	else {
2502
	    if (R_FINITE(line)) {
2544
	    if (R_FINITE(line)) {
2503
		vpos = line;
2545
		vpos = line;
2504
		adjy = 0;
2546
		adjy = 0;
2505
	    }
2547
	    }
2506
	    else {
2548
	    else {
2507
		vpos = 0.5 * Rf_gpptr(dd)->mar[2];
2549
		vpos = 0.5 * Rf_gpptr(dd)->mar[2];
2508
		adjy = 0.5;
2550
		adjy = 0.5;
2509
	    }
2551
	    }
2510
	    hpos = GConvertX(adj, NPC, USER, dd);
2552
	    hpos = GConvertX(adj, NPC, USER, dd);
2511
	    where = MAR3;
2553
	    where = MAR3;
2512
	}
2554
	}
2513
	if (isExpression(Main)) {
2555
	if (isExpression(Main)) {
2514
	    GMathText(hpos, vpos, where, VECTOR_ELT(Main, 0),
2556
	    GMathText(hpos, vpos, where, VECTOR_ELT(Main, 0),
2515
		      adj, 0.5, 0.0, dd);
2557
		      adj, 0.5, 0.0, dd);
2516
	}
2558
	}
2517
	else {
2559
	else {
2518
	  n = length(Main);
2560
	  n = length(Main);
2519
	  offset = 0.5 * (n - 1) + vpos;
2561
	  offset = 0.5 * (n - 1) + vpos;
2520
	  for (i = 0; i < n; i++) {
2562
	  for (i = 0; i < n; i++) {
2521
		string = STRING_ELT(Main, i);
2563
		string = STRING_ELT(Main, i);
2522
		if(string != NA_STRING)
2564
		if(string != NA_STRING)
2523
		    GText(hpos, offset - i, where, CHAR(string), adj,
2565
		    GText(hpos, offset - i, where, CHAR(string), adj,
2524
			  adjy, 0.0, dd);
2566
			  adjy, 0.0, dd);
2525
	  }
2567
	  }
2526
	}
2568
	}
2527
    }
2569
    }
2528
    if (sub != R_NilValue) {
2570
    if (sub != R_NilValue) {
2529
	cex = Rf_gpptr(dd)->cexsub;
2571
	cex = Rf_gpptr(dd)->cexsub;
2530
	col = Rf_gpptr(dd)->colsub;
2572
	col = Rf_gpptr(dd)->colsub;
2531
	font = Rf_gpptr(dd)->fontsub;
2573
	font = Rf_gpptr(dd)->fontsub;
2532
	GetTextArg(call, sub, &sub, &col, &cex, &font, &vfont);
2574
	GetTextArg(call, sub, &sub, &col, &cex, &font, &vfont);
2533
	Rf_gpptr(dd)->col = col;
2575
	Rf_gpptr(dd)->col = col;
2534
	Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * cex;
2576
	Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * cex;
2535
	Rf_gpptr(dd)->font = font;
2577
	Rf_gpptr(dd)->font = font;
2536
	if (R_FINITE(line))
2578
	if (R_FINITE(line))
2537
	    vpos = line;
2579
	    vpos = line;
2538
	else
2580
	else
2539
	    vpos = Rf_gpptr(dd)->mgp[0] + 1;
2581
	    vpos = Rf_gpptr(dd)->mgp[0] + 1;
2540
	if (outer) {
2582
	if (outer) {
2541
	    hpos = adj;
2583
	    hpos = adj;
2542
	    where = 1;
2584
	    where = 1;
2543
	}
2585
	}
2544
	else {
2586
	else {
2545
	    hpos = GConvertX(adj, NPC, USER, dd);
2587
	    hpos = GConvertX(adj, NPC, USER, dd);
2546
	    where = 0;
2588
	    where = 0;
2547
	}
2589
	}
2548
	if (isExpression(sub))
2590
	if (isExpression(sub))
2549
	    GMMathText(VECTOR_ELT(sub, 0), 1, vpos, where,
2591
	    GMMathText(VECTOR_ELT(sub, 0), 1, vpos, where,
2550
		       hpos, 0, dd);
2592
		       hpos, 0, dd);
2551
	else {
2593
	else {
2552
	    n = length(sub);
2594
	    n = length(sub);
2553
	    for (i = 0; i < n; i++) {
2595
	    for (i = 0; i < n; i++) {
2554
		string = STRING_ELT(sub, i);
2596
		string = STRING_ELT(sub, i);
2555
		if(string != NA_STRING)
2597
		if(string != NA_STRING)
2556
		    GMtext(CHAR(string), 1, vpos, where, hpos, 0, dd);
2598
		    GMtext(CHAR(string), 1, vpos, where, hpos, 0, dd);
2557
	    }
2599
	    }
2558
	}
2600
	}
2559
    }
2601
    }
2560
    if (xlab != R_NilValue) {
2602
    if (xlab != R_NilValue) {
2561
	cex = Rf_gpptr(dd)->cexlab;
2603
	cex = Rf_gpptr(dd)->cexlab;
2562
	col = Rf_gpptr(dd)->collab;
2604
	col = Rf_gpptr(dd)->collab;
2563
	font = Rf_gpptr(dd)->fontlab;
2605
	font = Rf_gpptr(dd)->fontlab;
2564
	GetTextArg(call, xlab, &xlab, &col, &cex, &font, &vfont);
2606
	GetTextArg(call, xlab, &xlab, &col, &cex, &font, &vfont);
2565
	Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * cex;
2607
	Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * cex;
2566
	Rf_gpptr(dd)->col = col;
2608
	Rf_gpptr(dd)->col = col;
2567
	Rf_gpptr(dd)->font = font;
2609
	Rf_gpptr(dd)->font = font;
2568
	if (R_FINITE(line))
2610
	if (R_FINITE(line))
2569
	    vpos = line;
2611
	    vpos = line;
2570
	else
2612
	else
2571
	    vpos = Rf_gpptr(dd)->mgp[0];
2613
	    vpos = Rf_gpptr(dd)->mgp[0];
2572
	if (outer) {
2614
	if (outer) {
2573
	    hpos = adj;
2615
	    hpos = adj;
2574
	    where = 1;
2616
	    where = 1;
2575
	}
2617
	}
2576
	else {
2618
	else {
2577
	    hpos = GConvertX(adj, NPC, USER, dd);
2619
	    hpos = GConvertX(adj, NPC, USER, dd);
2578
	    where = 0;
2620
	    where = 0;
2579
	}
2621
	}
2580
	if (isExpression(xlab))
2622
	if (isExpression(xlab))
2581
	    GMMathText(VECTOR_ELT(xlab, 0), 1, vpos, where,
2623
	    GMMathText(VECTOR_ELT(xlab, 0), 1, vpos, where,
2582
		       hpos, 0, dd);
2624
		       hpos, 0, dd);
2583
	else {
2625
	else {
2584
	    n = length(xlab);
2626
	    n = length(xlab);
2585
	    for (i = 0; i < n; i++) {
2627
	    for (i = 0; i < n; i++) {
2586
		string = STRING_ELT(xlab, i);
2628
		string = STRING_ELT(xlab, i);
2587
		if(string != NA_STRING)
2629
		if(string != NA_STRING)
2588
		    GMtext(CHAR(string), 1, vpos + i, where, hpos, 0, dd);
2630
		    GMtext(CHAR(string), 1, vpos + i, where, hpos, 0, dd);
2589
	    }
2631
	    }
2590
	}
2632
	}
2591
    }
2633
    }
2592
    if (ylab != R_NilValue) {
2634
    if (ylab != R_NilValue) {
2593
	cex = Rf_gpptr(dd)->cexlab;
2635
	cex = Rf_gpptr(dd)->cexlab;
2594
	col = Rf_gpptr(dd)->collab;
2636
	col = Rf_gpptr(dd)->collab;
2595
	font = Rf_gpptr(dd)->fontlab;
2637
	font = Rf_gpptr(dd)->fontlab;
2596
	GetTextArg(call, ylab, &ylab, &col, &cex, &font, &vfont);
2638
	GetTextArg(call, ylab, &ylab, &col, &cex, &font, &vfont);
2597
	Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * cex;
2639
	Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * cex;
2598
	Rf_gpptr(dd)->col = col;
2640
	Rf_gpptr(dd)->col = col;
2599
	Rf_gpptr(dd)->font = font;
2641
	Rf_gpptr(dd)->font = font;
2600
	if (R_FINITE(line))
2642
	if (R_FINITE(line))
2601
	    vpos = line;
2643
	    vpos = line;
2602
	else
2644
	else
2603
	    vpos = Rf_gpptr(dd)->mgp[0];
2645
	    vpos = Rf_gpptr(dd)->mgp[0];
2604
	if (outer) {
2646
	if (outer) {
2605
	    hpos = adj;
2647
	    hpos = adj;
2606
	    where = 1;
2648
	    where = 1;
2607
	}
2649
	}
2608
	else {
2650
	else {
2609
	    hpos = GConvertY(adj, NPC, USER, dd);
2651
	    hpos = GConvertY(adj, NPC, USER, dd);
2610
	    where = 0;
2652
	    where = 0;
2611
	}
2653
	}
2612
	if (isExpression(ylab))
2654
	if (isExpression(ylab))
2613
	    GMMathText(VECTOR_ELT(ylab, 0), 2, vpos, where,
2655
	    GMMathText(VECTOR_ELT(ylab, 0), 2, vpos, where,
2614
		       hpos, 0, dd);
2656
		       hpos, 0, dd);
2615
	else {
2657
	else {
2616
	    n = length(ylab);
2658
	    n = length(ylab);
2617
	    for (i = 0; i < n; i++) {
2659
	    for (i = 0; i < n; i++) {
2618
		string = STRING_ELT(ylab, i);
2660
		string = STRING_ELT(ylab, i);
2619
		if(string != NA_STRING)
2661
		if(string != NA_STRING)
2620
		    GMtext(CHAR(string), 2, vpos - i, where, hpos, 0, dd);
2662
		    GMtext(CHAR(string), 2, vpos - i, where, hpos, 0, dd);
2621
	    }
2663
	    }
2622
	}
2664
	}
2623
    }
2665
    }
2624
    GMode(0, dd);
2666
    GMode(0, dd);
2625
    GRestorePars(dd);
2667
    GRestorePars(dd);
2626
    /* NOTE: only record operation if no "error"  */
2668
    /* NOTE: only record operation if no "error"  */
2627
    if (GRecording(call))
2669
    if (GRecording(call))
2628
	recordGraphicOperation(op, originalArgs, dd);
2670
	recordGraphicOperation(op, originalArgs, dd);
2629
    return R_NilValue;
2671
    return R_NilValue;
2630
}
2672
}
2631
 
2673
 
2632
 
2674
 
2633
/*  abline(a, b, h, v, col, lty, lwd, ...)
2675
/*  abline(a, b, h, v, col, lty, lwd, ...)
2634
    draw lines in intercept/slope form.	 */
2676
    draw lines in intercept/slope form.	 */
2635
 
2677
 
2636
static void getxlimits(double *x, DevDesc *dd) {
2678
static void getxlimits(double *x, DevDesc *dd) {
2637
    /*
2679
    /*
2638
     * xpd = 0 means clip to current plot region
2680
     * xpd = 0 means clip to current plot region
2639
     * xpd = 1 means clip to current figure region
2681
     * xpd = 1 means clip to current figure region
2640
     * xpd = 2 means clip to device region
2682
     * xpd = 2 means clip to device region
2641
     */
2683
     */
2642
    switch (Rf_gpptr(dd)->xpd) {
2684
    switch (Rf_gpptr(dd)->xpd) {
2643
    case 0:
2685
    case 0:
2644
	x[0] = Rf_gpptr(dd)->usr[0];
2686
	x[0] = Rf_gpptr(dd)->usr[0];
2645
	x[1] = Rf_gpptr(dd)->usr[1];
2687
	x[1] = Rf_gpptr(dd)->usr[1];
2646
	break;
2688
	break;
2647
    case 1:
2689
    case 1:
2648
	x[0] = GConvertX(0, NFC, USER, dd);
2690
	x[0] = GConvertX(0, NFC, USER, dd);
2649
	x[1] = GConvertX(1, NFC, USER, dd);
2691
	x[1] = GConvertX(1, NFC, USER, dd);
2650
	break;
2692
	break;
2651
    case 2:
2693
    case 2:
2652
	x[0] = GConvertX(0, NDC, USER, dd);
2694
	x[0] = GConvertX(0, NDC, USER, dd);
2653
	x[1] = GConvertX(1, NDC, USER, dd);
2695
	x[1] = GConvertX(1, NDC, USER, dd);
2654
	break;
2696
	break;
2655
    }
2697
    }
2656
}
2698
}
2657
 
2699
 
2658
static void getylimits(double *y, DevDesc *dd) {
2700
static void getylimits(double *y, DevDesc *dd) {
2659
    switch (Rf_gpptr(dd)->xpd) {
2701
    switch (Rf_gpptr(dd)->xpd) {
2660
    case 0:
2702
    case 0:
2661
	y[0] = Rf_gpptr(dd)->usr[2];
2703
	y[0] = Rf_gpptr(dd)->usr[2];
2662
	y[1] = Rf_gpptr(dd)->usr[3];
2704
	y[1] = Rf_gpptr(dd)->usr[3];
2663
	break;
2705
	break;
2664
    case 1:
2706
    case 1:
2665
	y[0] = GConvertY(0, NFC, USER, dd);
2707
	y[0] = GConvertY(0, NFC, USER, dd);
2666
	y[1] = GConvertY(1, NFC, USER, dd);
2708
	y[1] = GConvertY(1, NFC, USER, dd);
2667
	break;
2709
	break;
2668
    case 2:
2710
    case 2:
2669
	y[0] = GConvertY(0, NDC, USER, dd);
2711
	y[0] = GConvertY(0, NDC, USER, dd);
2670
	y[1] = GConvertY(1, NDC, USER, dd);
2712
	y[1] = GConvertY(1, NDC, USER, dd);
2671
	break;
2713
	break;
2672
    }
2714
    }
2673
}
2715
}
2674
 
2716
 
2675
SEXP do_abline(SEXP call, SEXP op, SEXP args, SEXP env)
2717
SEXP do_abline(SEXP call, SEXP op, SEXP args, SEXP env)
2676
{
2718
{
2677
    SEXP a, b, h, v, untf, col, lty, lwd;
2719
    SEXP a, b, h, v, untf, col, lty, lwd;
2678
    int i, ncol, nlines, nlty, nlwd, lstart, lstop;
2720
    int i, ncol, nlines, nlty, nlwd, lstart, lstop;
2679
    double aa, bb, x[2], y[2];
2721
    double aa, bb, x[2], y[2];
2680
    SEXP originalArgs = args;
2722
    SEXP originalArgs = args;
2681
    DevDesc *dd = CurrentDevice();
2723
    DevDesc *dd = CurrentDevice();
2682
 
2724
 
2683
    GCheckState(dd);
2725
    GCheckState(dd);
2684
 
2726
 
2685
    if (length(args) < 5) errorcall(call, "too few arguments");
2727
    if (length(args) < 5) errorcall(call, "too few arguments");
2686
 
2728
 
2687
    if ((a = CAR(args)) != R_NilValue)
2729
    if ((a = CAR(args)) != R_NilValue)
2688
	SETCAR(args, a = coerceVector(a, REALSXP));
2730
	SETCAR(args, a = coerceVector(a, REALSXP));
2689
    args = CDR(args);
2731
    args = CDR(args);
2690
 
2732
 
2691
    if ((b = CAR(args)) != R_NilValue)
2733
    if ((b = CAR(args)) != R_NilValue)
2692
	SETCAR(args, b = coerceVector(b, REALSXP));
2734
	SETCAR(args, b = coerceVector(b, REALSXP));
2693
    args = CDR(args);
2735
    args = CDR(args);
2694
 
2736
 
2695
    if ((h = CAR(args)) != R_NilValue)
2737
    if ((h = CAR(args)) != R_NilValue)
2696
	SETCAR(args, h = coerceVector(h, REALSXP));
2738
	SETCAR(args, h = coerceVector(h, REALSXP));
2697
    args = CDR(args);
2739
    args = CDR(args);
2698
 
2740
 
2699
    if ((v = CAR(args)) != R_NilValue)
2741
    if ((v = CAR(args)) != R_NilValue)
2700
	SETCAR(args, v = coerceVector(v, REALSXP));
2742
	SETCAR(args, v = coerceVector(v, REALSXP));
2701
    args = CDR(args);
2743
    args = CDR(args);
2702
 
2744
 
2703
    if ((untf = CAR(args)) != R_NilValue)
2745
    if ((untf = CAR(args)) != R_NilValue)
2704
	SETCAR(args, untf = coerceVector(untf, LGLSXP));
2746
	SETCAR(args, untf = coerceVector(untf, LGLSXP));
2705
    args = CDR(args);
2747
    args = CDR(args);
2706
 
2748
 
2707
 
2749
 
2708
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));	args = CDR(args);
2750
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));	args = CDR(args);
2709
    ncol = LENGTH(col);
2751
    ncol = LENGTH(col);
2710
 
2752
 
2711
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty)); args = CDR(args);
2753
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty)); args = CDR(args);
2712
    nlty = length(lty);
2754
    nlty = length(lty);
2713
 
2755
 
2714
    PROTECT(lwd = FixupLwd(CAR(args), Rf_gpptr(dd)->lwd)); args = CDR(args);
2756
    PROTECT(lwd = FixupLwd(CAR(args), Rf_gpptr(dd)->lwd)); args = CDR(args);
2715
    nlwd = length(lwd);
2757
    nlwd = length(lwd);
2716
 
2758
 
2717
    GSavePars(dd);
2759
    GSavePars(dd);
2718
 
2760
 
2719
    ProcessInlinePars(args, dd, call);
2761
    ProcessInlinePars(args, dd, call);
2720
 
2762
 
2721
    nlines = 0;
2763
    nlines = 0;
2722
 
2764
 
2723
    if (a != R_NilValue) {
2765
    if (a != R_NilValue) {
2724
	if (b == R_NilValue) {
2766
	if (b == R_NilValue) {
2725
	    if (LENGTH(a) != 2)
2767
	    if (LENGTH(a) != 2)
2726
		errorcall(call, "invalid a=, b= specification");
2768
		errorcall(call, "invalid a=, b= specification");
2727
	    aa = REAL(a)[0];
2769
	    aa = REAL(a)[0];
2728
	    bb = REAL(a)[1];
2770
	    bb = REAL(a)[1];
2729
	}
2771
	}
2730
	else {
2772
	else {
2731
	    aa = asReal(a);
2773
	    aa = asReal(a);
2732
	    bb = asReal(b);
2774
	    bb = asReal(b);
2733
	}
2775
	}
2734
	if (!R_FINITE(aa) || !R_FINITE(bb))
2776
	if (!R_FINITE(aa) || !R_FINITE(bb))
2735
	    errorcall(call, "\"a\" and \"b\" must be finite");
2777
	    errorcall(call, "\"a\" and \"b\" must be finite");
2736
	Rf_gpptr(dd)->col = INTEGER(col)[0];
2778
	Rf_gpptr(dd)->col = INTEGER(col)[0];
2737
	Rf_gpptr(dd)->lwd = REAL(lwd)[0];
2779
	Rf_gpptr(dd)->lwd = REAL(lwd)[0];
2738
	if (nlty && INTEGER(lty)[0] != NA_INTEGER)
2780
	if (nlty && INTEGER(lty)[0] != NA_INTEGER)
2739
	    Rf_gpptr(dd)->lty = INTEGER(lty)[0];
2781
	    Rf_gpptr(dd)->lty = INTEGER(lty)[0];
2740
	else
2782
	else
2741
	    Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
2783
	    Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
2742
	GMode(1, dd);
2784
	GMode(1, dd);
2743
	/* FIXME?
2785
	/* FIXME?
2744
	 * Seems like the logic here is just draw from xmin to xmax
2786
	 * Seems like the logic here is just draw from xmin to xmax
2745
	 * and you're guaranteed to draw at least from ymin to ymax
2787
	 * and you're guaranteed to draw at least from ymin to ymax
2746
	 * This MAY cause a problem at some stage when the line being
2788
	 * This MAY cause a problem at some stage when the line being
2747
	 * drawn is VERY steep -- and the problem is worse now that
2789
	 * drawn is VERY steep -- and the problem is worse now that
2748
	 * abline will potentially draw to the extents of the device
2790
	 * abline will potentially draw to the extents of the device
2749
	 * (when xpd=NA).  NOTE that R's internal clipping protects the
2791
	 * (when xpd=NA).  NOTE that R's internal clipping protects the
2750
	 * device drivers from stupidly large numbers, BUT there is
2792
	 * device drivers from stupidly large numbers, BUT there is
2751
	 * still a risk that we could produce a number which is too
2793
	 * still a risk that we could produce a number which is too
2752
	 * big for the computer's brain.
2794
	 * big for the computer's brain.
2753
	 * Paul.
2795
	 * Paul.
2754
	 *
2796
	 *
2755
	 * The problem is worse -- you could get NaN, which at least the
2797
	 * The problem is worse -- you could get NaN, which at least the
2756
	 * X11 device coerces to -2^31 <TSL>
2798
	 * X11 device coerces to -2^31 <TSL>
2757
	 */
2799
	 */
2758
	getxlimits(x, dd);
2800
	getxlimits(x, dd);
2759
	if (R_FINITE(Rf_gpptr(dd)->lwd)) {
2801
	if (R_FINITE(Rf_gpptr(dd)->lwd)) {
2760
	    if (LOGICAL(untf)[0] == 1 && (Rf_gpptr(dd)->xlog || Rf_gpptr(dd)->ylog)) {
2802
	    if (LOGICAL(untf)[0] == 1 && (Rf_gpptr(dd)->xlog || Rf_gpptr(dd)->ylog)) {
2761
		double xx[101], yy[101];
2803
		double xx[101], yy[101];
2762
		double xstep = (x[1] - x[0])/100;
2804
		double xstep = (x[1] - x[0])/100;
2763
		for (i = 0; i < 100; i++) {
2805
		for (i = 0; i < 100; i++) {
2764
		    xx[i] = x[0] + i*xstep;
2806
		    xx[i] = x[0] + i*xstep;
2765
		    yy[i] = aa + xx[i] * bb;
2807
		    yy[i] = aa + xx[i] * bb;
2766
		}
2808
		}
2767
		xx[100] = x[1];
2809
		xx[100] = x[1];
2768
		yy[100] = aa + x[1] * bb;
2810
		yy[100] = aa + x[1] * bb;
2769
 
2811
 
2770
		/* now get rid of -ve values */
2812
		/* now get rid of -ve values */
2771
		lstart=0;lstop=100;
2813
		lstart=0;lstop=100;
2772
		if (Rf_gpptr(dd)->xlog){
2814
		if (Rf_gpptr(dd)->xlog){
2773
			for(;xx[lstart]<=0 && lstart<101;lstart++);
2815
			for(;xx[lstart]<=0 && lstart<101;lstart++);
2774
			for(;xx[lstop]<=0 && lstop>0;lstop--);
2816
			for(;xx[lstop]<=0 && lstop>0;lstop--);
2775
		}
2817
		}
2776
		if (Rf_gpptr(dd)->ylog){
2818
		if (Rf_gpptr(dd)->ylog){
2777
			for(;yy[lstart]<=0 && lstart<101;lstart++);
2819
			for(;yy[lstart]<=0 && lstart<101;lstart++);
2778
			for(;yy[lstop]<=0 && lstop>0;lstop--);
2820
			for(;yy[lstop]<=0 && lstop>0;lstop--);
2779
		}
2821
		}
2780
 
2822
 
2781
 
2823
 
2782
		GPolyline(lstop-lstart+1, xx+lstart, yy+lstart, USER, dd);
2824
		GPolyline(lstop-lstart+1, xx+lstart, yy+lstart, USER, dd);
2783
	    }
2825
	    }
2784
	    else {
2826
	    else {
2785
		double x0, x1;
2827
		double x0, x1;
2786
 
2828
 
2787
		x0 = ( Rf_gpptr(dd)->xlog ) ?	log10(x[0]) : x[0];
2829
		x0 = ( Rf_gpptr(dd)->xlog ) ?	log10(x[0]) : x[0];
2788
		x1 = ( Rf_gpptr(dd)->xlog ) ?	log10(x[1]) : x[1];
2830
		x1 = ( Rf_gpptr(dd)->xlog ) ?	log10(x[1]) : x[1];
2789
 
2831
 
2790
		y[0] = aa + x0 * bb;
2832
		y[0] = aa + x0 * bb;
2791
		y[1] = aa + x1 * bb;
2833
		y[1] = aa + x1 * bb;
2792
 
2834
 
2793
		if ( Rf_gpptr(dd)->ylog ){
2835
		if ( Rf_gpptr(dd)->ylog ){
2794
		    y[0] = pow(10.,y[0]);
2836
		    y[0] = pow(10.,y[0]);
2795
		    y[1] = pow(10.,y[1]);
2837
		    y[1] = pow(10.,y[1]);
2796
		}
2838
		}
2797
 
2839
 
2798
		GLine(x[0], y[0], x[1], y[1], USER, dd);
2840
		GLine(x[0], y[0], x[1], y[1], USER, dd);
2799
	    }
2841
	    }
2800
	}
2842
	}
2801
	GMode(0, dd);
2843
	GMode(0, dd);
2802
	nlines++;
2844
	nlines++;
2803
    }
2845
    }
2804
    if (h != R_NilValue) {
2846
    if (h != R_NilValue) {
2805
	GMode(1, dd);
2847
	GMode(1, dd);
2806
	for (i = 0; i < LENGTH(h); i++) {
2848
	for (i = 0; i < LENGTH(h); i++) {
2807
	    Rf_gpptr(dd)->col = INTEGER(col)[nlines % ncol];
2849
	    Rf_gpptr(dd)->col = INTEGER(col)[nlines % ncol];
2808
	    if (nlty && INTEGER(lty)[nlines % nlty] != NA_INTEGER)
2850
	    if (nlty && INTEGER(lty)[nlines % nlty] != NA_INTEGER)
2809
		Rf_gpptr(dd)->lty = INTEGER(lty)[nlines % nlty];
2851
		Rf_gpptr(dd)->lty = INTEGER(lty)[nlines % nlty];
2810
	    else
2852
	    else
2811
		Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
2853
		Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
2812
	    Rf_gpptr(dd)->lwd = REAL(lwd)[nlines % nlwd];
2854
	    Rf_gpptr(dd)->lwd = REAL(lwd)[nlines % nlwd];
2813
	    aa = REAL(h)[i];
2855
	    aa = REAL(h)[i];
2814
	    if (R_FINITE(aa) && R_FINITE(Rf_gpptr(dd)->lwd)) {
2856
	    if (R_FINITE(aa) && R_FINITE(Rf_gpptr(dd)->lwd)) {
2815
		getxlimits(x, dd);
2857
		getxlimits(x, dd);
2816
		y[0] = aa;
2858
		y[0] = aa;
2817
		y[1] = aa;
2859
		y[1] = aa;
2818
		GLine(x[0], y[0], x[1], y[1], USER, dd);
2860
		GLine(x[0], y[0], x[1], y[1], USER, dd);
2819
	    }
2861
	    }
2820
	    nlines++;
2862
	    nlines++;
2821
	}
2863
	}
2822
	GMode(0, dd);
2864
	GMode(0, dd);
2823
    }
2865
    }
2824
    if (v != R_NilValue) {
2866
    if (v != R_NilValue) {
2825
	GMode(1, dd);
2867
	GMode(1, dd);
2826
	for (i = 0; i < LENGTH(v); i++) {
2868
	for (i = 0; i < LENGTH(v); i++) {
2827
	    Rf_gpptr(dd)->col = INTEGER(col)[nlines % ncol];
2869
	    Rf_gpptr(dd)->col = INTEGER(col)[nlines % ncol];
2828
	    if (nlty && INTEGER(lty)[nlines % nlty] != NA_INTEGER)
2870
	    if (nlty && INTEGER(lty)[nlines % nlty] != NA_INTEGER)
2829
		Rf_gpptr(dd)->lty = INTEGER(lty)[nlines % nlty];
2871
		Rf_gpptr(dd)->lty = INTEGER(lty)[nlines % nlty];
2830
	    else
2872
	    else
2831
		Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
2873
		Rf_gpptr(dd)->lty = Rf_dpptr(dd)->lty;
2832
	    Rf_gpptr(dd)->lwd = REAL(lwd)[nlines % nlwd];
2874
	    Rf_gpptr(dd)->lwd = REAL(lwd)[nlines % nlwd];
2833
	    aa = REAL(v)[i];
2875
	    aa = REAL(v)[i];
2834
	    if (R_FINITE(aa) && R_FINITE(Rf_gpptr(dd)->lwd)) {
2876
	    if (R_FINITE(aa) && R_FINITE(Rf_gpptr(dd)->lwd)) {
2835
		getylimits(y, dd);
2877
		getylimits(y, dd);
2836
		x[0] = aa;
2878
		x[0] = aa;
2837
		x[1] = aa;
2879
		x[1] = aa;
2838
		GLine(x[0], y[0], x[1], y[1], USER, dd);
2880
		GLine(x[0], y[0], x[1], y[1], USER, dd);
2839
	    }
2881
	    }
2840
	    nlines++;
2882
	    nlines++;
2841
	}
2883
	}
2842
	GMode(0, dd);
2884
	GMode(0, dd);
2843
    }
2885
    }
2844
    UNPROTECT(3);
2886
    UNPROTECT(3);
2845
    GRestorePars(dd);
2887
    GRestorePars(dd);
2846
    /* NOTE: only record operation if no "error"  */
2888
    /* NOTE: only record operation if no "error"  */
2847
    if (GRecording(call))
2889
    if (GRecording(call))
2848
	recordGraphicOperation(op, originalArgs, dd);
2890
	recordGraphicOperation(op, originalArgs, dd);
2849
    return R_NilValue;
2891
    return R_NilValue;
2850
}
2892
}
2851
 
2893
 
2852
SEXP do_box(SEXP call, SEXP op, SEXP args, SEXP env)
2894
SEXP do_box(SEXP call, SEXP op, SEXP args, SEXP env)
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 */
2876
    Rf_gpptr(dd)->xpd = 2;
2927
    Rf_gpptr(dd)->xpd = 2;
2877
    GMode(1, dd);
2928
    GMode(1, dd);
2878
    GBox(which, dd);
2929
    GBox(which, dd);
2879
    GMode(0, dd);
2930
    GMode(0, dd);
2880
    GRestorePars(dd);
2931
    GRestorePars(dd);
2881
    /* NOTE: only record operation if no "error"  */
2932
    /* NOTE: only record operation if no "error"  */
2882
    if (GRecording(call))
2933
    if (GRecording(call))
2883
	recordGraphicOperation(op, originalArgs, dd);
2934
	recordGraphicOperation(op, originalArgs, dd);
2884
    return R_NilValue;
2935
    return R_NilValue;
2885
}
2936
}
2886
 
2937
 
2887
static void drawPointsLines(double xp, double yp, double xold, double yold,
2938
static void drawPointsLines(double xp, double yp, double xold, double yold,
2888
			    char type, int first, DevDesc *dd)
2939
			    char type, int first, DevDesc *dd)
2889
{
2940
{
2890
    if (type == 'p' || type == 'o')
2941
    if (type == 'p' || type == 'o')
2891
	GSymbol(xp, yp, DEVICE, Rf_gpptr(dd)->pch, dd);
2942
	GSymbol(xp, yp, DEVICE, Rf_gpptr(dd)->pch, dd);
2892
    if ((type == 'l' || type == 'o') && !first)
2943
    if ((type == 'l' || type == 'o') && !first)
2893
	GLine(xold, yold, xp, yp, DEVICE, dd);
2944
	GLine(xold, yold, xp, yp, DEVICE, dd);
2894
}
2945
}
2895
 
2946
 
2896
SEXP do_locator(SEXP call, SEXP op, SEXP args, SEXP env)
2947
SEXP do_locator(SEXP call, SEXP op, SEXP args, SEXP env)
2897
{
2948
{
2898
    SEXP x, y, nobs, ans, saveans, stype = R_NilValue;
2949
    SEXP x, y, nobs, ans, saveans, stype = R_NilValue;
2899
    int i, n, type='p';
2950
    int i, n, type='p';
2900
    double xp, yp, xold=0, yold=0;
2951
    double xp, yp, xold=0, yold=0;
2901
    DevDesc *dd = CurrentDevice();
2952
    DevDesc *dd = CurrentDevice();
2902
 
2953
 
2903
    /* If replaying, just draw the points and lines that were recorded */
2954
    /* If replaying, just draw the points and lines that were recorded */
2904
    if (call == R_NilValue) {
2955
    if (call == R_NilValue) {
2905
	x = CAR(args); args = CDR(args);
2956
	x = CAR(args); args = CDR(args);
2906
	y = CAR(args); args = CDR(args);
2957
	y = CAR(args); args = CDR(args);
2907
	nobs = CAR(args); args = CDR(args);
2958
	nobs = CAR(args); args = CDR(args);
2908
	n = INTEGER(nobs)[0];
2959
	n = INTEGER(nobs)[0];
2909
	stype = CAR(args); args = CDR(args);
2960
	stype = CAR(args); args = CDR(args);
2910
	type = CHAR(STRING_ELT(stype, 0))[0];
2961
	type = CHAR(STRING_ELT(stype, 0))[0];
2911
	if (type != 'n') {
2962
	if (type != 'n') {
2912
	    GMode(1, dd);
2963
	    GMode(1, dd);
2913
	    for (i=0; i<n; i++) {
2964
	    for (i=0; i<n; i++) {
2914
		xp = REAL(x)[i];
2965
		xp = REAL(x)[i];
2915
		yp = REAL(y)[i];
2966
		yp = REAL(y)[i];
2916
		GConvert(&xp, &yp, USER, DEVICE, dd);
2967
		GConvert(&xp, &yp, USER, DEVICE, dd);
2917
		drawPointsLines(xp, yp, xold, yold, type, i==0, dd);
2968
		drawPointsLines(xp, yp, xold, yold, type, i==0, dd);
2918
		xold = xp;
2969
		xold = xp;
2919
		yold = yp;
2970
		yold = yp;
2920
	    }
2971
	    }
2921
	    GMode(0, dd);
2972
	    GMode(0, dd);
2922
	}
2973
	}
2923
	return R_NilValue;
2974
	return R_NilValue;
2924
    } else {
2975
    } else {
2925
	GCheckState(dd);
2976
	GCheckState(dd);
2926
 
2977
 
2927
	checkArity(op, args);
2978
	checkArity(op, args);
2928
	n = asInteger(CAR(args));
2979
	n = asInteger(CAR(args));
2929
	if (n <= 0 || n == NA_INTEGER)
2980
	if (n <= 0 || n == NA_INTEGER)
2930
	    error("invalid number of points in locator");
2981
	    error("invalid number of points in locator");
2931
	args = CDR(args);
2982
	args = CDR(args);
2932
	if (isString(CAR(args)) && LENGTH(CAR(args)) == 1)
2983
	if (isString(CAR(args)) && LENGTH(CAR(args)) == 1)
2933
	    stype = CAR(args);
2984
	    stype = CAR(args);
2934
	else
2985
	else
2935
	    errorcall(call, "invalid plot type");
2986
	    errorcall(call, "invalid plot type");
2936
	type = CHAR(STRING_ELT(stype, 0))[0];
2987
	type = CHAR(STRING_ELT(stype, 0))[0];
2937
	PROTECT(x = allocVector(REALSXP, n));
2988
	PROTECT(x = allocVector(REALSXP, n));
2938
	PROTECT(y = allocVector(REALSXP, n));
2989
	PROTECT(y = allocVector(REALSXP, n));
2939
	PROTECT(nobs=allocVector(INTSXP,1));
2990
	PROTECT(nobs=allocVector(INTSXP,1));
2940
	i = 0;
2991
	i = 0;
2941
 
2992
 
2942
	GMode(2, dd);
2993
	GMode(2, dd);
2943
	while (i < n) {
2994
	while (i < n) {
2944
	    if (!GLocator(&(REAL(x)[i]), &(REAL(y)[i]), USER, dd))
2995
	    if (!GLocator(&(REAL(x)[i]), &(REAL(y)[i]), USER, dd))
2945
		break;
2996
		break;
2946
	    if (type != 'n') {
2997
	    if (type != 'n') {
2947
		GMode(1, dd);
2998
		GMode(1, dd);
2948
		xp = REAL(x)[i];
2999
		xp = REAL(x)[i];
2949
		yp = REAL(y)[i];
3000
		yp = REAL(y)[i];
2950
		GConvert(&xp, &yp, USER, DEVICE, dd);
3001
		GConvert(&xp, &yp, USER, DEVICE, dd);
2951
		drawPointsLines(xp, yp, xold, yold, type, i==0, dd);
3002
		drawPointsLines(xp, yp, xold, yold, type, i==0, dd);
2952
		GMode(2, dd);
3003
		GMode(2, dd);
2953
		xold = xp; yold = yp;
3004
		xold = xp; yold = yp;
2954
	    }
3005
	    }
2955
	    i += 1;
3006
	    i += 1;
2956
	}
3007
	}
2957
	GMode(0, dd);
3008
	GMode(0, dd);
2958
	INTEGER(nobs)[0] = i;
3009
	INTEGER(nobs)[0] = i;
2959
	while (i < n) {
3010
	while (i < n) {
2960
	    REAL(x)[i] = NA_REAL;
3011
	    REAL(x)[i] = NA_REAL;
2961
	    REAL(y)[i] = NA_REAL;
3012
	    REAL(y)[i] = NA_REAL;
2962
	    i += 1;
3013
	    i += 1;
2963
	}
3014
	}
2964
	PROTECT(ans = allocList(3));
3015
	PROTECT(ans = allocList(3));
2965
	SETCAR(ans, x);
3016
	SETCAR(ans, x);
2966
	SETCADR(ans, y);
3017
	SETCADR(ans, y);
2967
	SETCADDR(ans, nobs);
3018
	SETCADDR(ans, nobs);
2968
	PROTECT(saveans = allocList(4));
3019
	PROTECT(saveans = allocList(4));
2969
	SETCAR(saveans, x);
3020
	SETCAR(saveans, x);
2970
	SETCADR(saveans, y);
3021
	SETCADR(saveans, y);
2971
	SETCADDR(saveans, nobs);
3022
	SETCADDR(saveans, nobs);
2972
	SETCADDDR(saveans, CAR(args));
3023
	SETCADDDR(saveans, CAR(args));
2973
	/* Record the points and lines that were drawn in the display list */
3024
	/* Record the points and lines that were drawn in the display list */
2974
	recordGraphicOperation(op, saveans, dd);
3025
	recordGraphicOperation(op, saveans, dd);
2975
	UNPROTECT(5);
3026
	UNPROTECT(5);
2976
	return ans;
3027
	return ans;
2977
    }
3028
    }
2978
}
3029
}
2979
 
3030
 
2980
#define THRESHOLD	0.25
3031
#define THRESHOLD	0.25
2981
 
3032
 
2982
static void drawLabel(double xi, double yi, int pos, double offset, char *l,
3033
static void drawLabel(double xi, double yi, int pos, double offset, char *l,
2983
		      DevDesc *dd)
3034
		      DevDesc *dd)
2984
{
3035
{
2985
    switch (pos) {
3036
    switch (pos) {
2986
    case 4:
3037
    case 4:
2987
	xi = xi+offset;
3038
	xi = xi+offset;
2988
	GText(xi, yi, INCHES, l, 0.0,
3039
	GText(xi, yi, INCHES, l, 0.0,
2989
	      Rf_gpptr(dd)->yCharOffset, 0.0, dd);
3040
	      Rf_gpptr(dd)->yCharOffset, 0.0, dd);
2990
	break;
3041
	break;
2991
    case 2:
3042
    case 2:
2992
	xi = xi-offset;
3043
	xi = xi-offset;
2993
	GText(xi, yi, INCHES, l, 1.0,
3044
	GText(xi, yi, INCHES, l, 1.0,
2994
	      Rf_gpptr(dd)->yCharOffset, 0.0, dd);
3045
	      Rf_gpptr(dd)->yCharOffset, 0.0, dd);
2995
	break;
3046
	break;
2996
    case 3:
3047
    case 3:
2997
	yi = yi+offset;
3048
	yi = yi+offset;
2998
	GText(xi, yi, INCHES, l, 0.5,
3049
	GText(xi, yi, INCHES, l, 0.5,
2999
	      0.0, 0.0, dd);
3050
	      0.0, 0.0, dd);
3000
	break;
3051
	break;
3001
    case 1:
3052
    case 1:
3002
	yi = yi-offset;
3053
	yi = yi-offset;
3003
	GText(xi, yi, INCHES, l, 0.5,
3054
	GText(xi, yi, INCHES, l, 0.5,
3004
	      1-(0.5-Rf_gpptr(dd)->yCharOffset),
3055
	      1-(0.5-Rf_gpptr(dd)->yCharOffset),
3005
	      0.0, dd);
3056
	      0.0, dd);
3006
    }
3057
    }
3007
}
3058
}
3008
 
3059
 
3009
SEXP do_identify(SEXP call, SEXP op, SEXP args, SEXP env)
3060
SEXP do_identify(SEXP call, SEXP op, SEXP args, SEXP env)
3010
{
3061
{
3011
    SEXP ans, x, y, l, ind, pos, Offset, draw, saveans;
3062
    SEXP ans, x, y, l, ind, pos, Offset, draw, saveans;
3012
    double xi, yi, xp, yp, d, dmin, offset;
3063
    double xi, yi, xp, yp, d, dmin, offset;
3013
    int i, imin, k, n, npts, plot, posi, warn;
3064
    int i, imin, k, n, npts, plot, posi, warn;
3014
    DevDesc *dd = CurrentDevice();
3065
    DevDesc *dd = CurrentDevice();
3015
 
3066
 
3016
    /* If we are replaying the display list, then just redraw the
3067
    /* If we are replaying the display list, then just redraw the
3017
       labels beside the identified points */
3068
       labels beside the identified points */
3018
    if (call == R_NilValue) {
3069
    if (call == R_NilValue) {
3019
	ind = CAR(args); args = CDR(args);
3070
	ind = CAR(args); args = CDR(args);
3020
	pos = CAR(args); args = CDR(args);
3071
	pos = CAR(args); args = CDR(args);
3021
	x = CAR(args); args = CDR(args);
3072
	x = CAR(args); args = CDR(args);
3022
	y = CAR(args); args = CDR(args);
3073
	y = CAR(args); args = CDR(args);
3023
	Offset = CAR(args); args = CDR(args);
3074
	Offset = CAR(args); args = CDR(args);
3024
	l = CAR(args); args = CDR(args);
3075
	l = CAR(args); args = CDR(args);
3025
	draw = CAR(args);
3076
	draw = CAR(args);
3026
	n = length(x);
3077
	n = length(x);
3027
	for (i=0; i<n; i++) {
3078
	for (i=0; i<n; i++) {
3028
	    plot = LOGICAL(ind)[i];
3079
	    plot = LOGICAL(ind)[i];
3029
	    if (LOGICAL(draw)[0] && plot) {
3080
	    if (LOGICAL(draw)[0] && plot) {
3030
		xi = REAL(x)[i];
3081
		xi = REAL(x)[i];
3031
		yi = REAL(y)[i];
3082
		yi = REAL(y)[i];
3032
		GConvert(&xi, &yi, USER, INCHES, dd);
3083
		GConvert(&xi, &yi, USER, INCHES, dd);
3033
		posi = INTEGER(pos)[i];
3084
		posi = INTEGER(pos)[i];
3034
		offset = GConvertXUnits(asReal(Offset), CHARS, INCHES, dd);
3085
		offset = GConvertXUnits(asReal(Offset), CHARS, INCHES, dd);
3035
		drawLabel(xi, yi, posi, offset, CHAR(STRING_ELT(l, i)), dd);
3086
		drawLabel(xi, yi, posi, offset, CHAR(STRING_ELT(l, i)), dd);
3036
	    }
3087
	    }
3037
	}
3088
	}
3038
	return R_NilValue;
3089
	return R_NilValue;
3039
    }
3090
    }
3040
    else {
3091
    else {
3041
	GCheckState(dd);
3092
	GCheckState(dd);
3042
 
3093
 
3043
	checkArity(op, args);
3094
	checkArity(op, args);
3044
	x = CAR(args);
3095
	x = CAR(args);
3045
	args = CDR(args); y = CAR(args);
3096
	args = CDR(args); y = CAR(args);
3046
	args = CDR(args); l = CAR(args);
3097
	args = CDR(args); l = CAR(args);
3047
	args = CDR(args); npts = asInteger(CAR(args));
3098
	args = CDR(args); npts = asInteger(CAR(args));
3048
	args = CDR(args); plot = asLogical(CAR(args));
3099
	args = CDR(args); plot = asLogical(CAR(args));
3049
	args = CDR(args); Offset = CAR(args);
3100
	args = CDR(args); Offset = CAR(args);
3050
	if (npts <= 0 || npts == NA_INTEGER)
3101
	if (npts <= 0 || npts == NA_INTEGER)
3051
	    error("invalid number of points in identify");
3102
	    error("invalid number of points in identify");
3052
	if (!isReal(x) || !isReal(y) || !isString(l) || !isReal(Offset))
3103
	if (!isReal(x) || !isReal(y) || !isString(l) || !isReal(Offset))
3053
	    errorcall(call, "incorrect argument type");
3104
	    errorcall(call, "incorrect argument type");
3054
	if (LENGTH(x) != LENGTH(y) || LENGTH(x) != LENGTH(l))
3105
	if (LENGTH(x) != LENGTH(y) || LENGTH(x) != LENGTH(l))
3055
	    errorcall(call, "different argument lengths");
3106
	    errorcall(call, "different argument lengths");
3056
	n = LENGTH(x);
3107
	n = LENGTH(x);
3057
	if (n <= 0) {
3108
	if (n <= 0) {
3058
	    R_Visible = 0;
3109
	    R_Visible = 0;
3059
	    return NULL;
3110
	    return NULL;
3060
	}
3111
	}
3061
 
3112
 
3062
	offset = GConvertXUnits(asReal(Offset), CHARS, INCHES, dd);
3113
	offset = GConvertXUnits(asReal(Offset), CHARS, INCHES, dd);
3063
	PROTECT(ind = allocVector(LGLSXP, n));
3114
	PROTECT(ind = allocVector(LGLSXP, n));
3064
	PROTECT(pos = allocVector(INTSXP, n));
3115
	PROTECT(pos = allocVector(INTSXP, n));
3065
	for (i = 0; i < n; i++)
3116
	for (i = 0; i < n; i++)
3066
	    LOGICAL(ind)[i] = 0;
3117
	    LOGICAL(ind)[i] = 0;
3067
 
3118
 
3068
	k = 0;
3119
	k = 0;
3069
	GMode(2, dd);
3120
	GMode(2, dd);
3070
	while (k < npts) {
3121
	while (k < npts) {
3071
	    if (!GLocator(&xp, &yp, INCHES, dd)) break;
3122
	    if (!GLocator(&xp, &yp, INCHES, dd)) break;
3072
	    dmin = DBL_MAX;
3123
	    dmin = DBL_MAX;
3073
	    imin = -1;
3124
	    imin = -1;
3074
	    for (i = 0; i < n; i++) {
3125
	    for (i = 0; i < n; i++) {
3075
		xi = REAL(x)[i];
3126
		xi = REAL(x)[i];
3076
		yi = REAL(y)[i];
3127
		yi = REAL(y)[i];
3077
		GConvert(&xi, &yi, USER, INCHES, dd);
3128
		GConvert(&xi, &yi, USER, INCHES, dd);
3078
		if (!R_FINITE(xi) || !R_FINITE(yi)) continue;
3129
		if (!R_FINITE(xi) || !R_FINITE(yi)) continue;
3079
		d = hypot(xp-xi, yp-yi);
3130
		d = hypot(xp-xi, yp-yi);
3080
		if (d < dmin) {
3131
		if (d < dmin) {
3081
		    imin = i;
3132
		    imin = i;
3082
		    dmin = d;
3133
		    dmin = d;
3083
		}
3134
		}
3084
	    }
3135
	    }
3085
	    /* can't use warning because we want to print immediately  */
3136
	    /* can't use warning because we want to print immediately  */
3086
	    /* might want to handle warn=2? */
3137
	    /* might want to handle warn=2? */
3087
	    warn = asInteger(GetOption(install("warn"), R_NilValue));
3138
	    warn = asInteger(GetOption(install("warn"), R_NilValue));
3088
	    if (dmin > THRESHOLD) {
3139
	    if (dmin > THRESHOLD) {
3089
	        if(warn >= 0)
3140
	        if(warn >= 0)
3090
		    REprintf("warning: no point with %.2f inches\n",
3141
		    REprintf("warning: no point with %.2f inches\n",
3091
                                        THRESHOLD);
3142
                                        THRESHOLD);
3092
	    }
3143
	    }
3093
	    else if (LOGICAL(ind)[imin]) {
3144
	    else if (LOGICAL(ind)[imin]) {
3094
	        if(warn >= 0 )
3145
	        if(warn >= 0 )
3095
		    REprintf("warning: nearest point already identified\n");
3146
		    REprintf("warning: nearest point already identified\n");
3096
	    }
3147
	    }
3097
	    else {
3148
	    else {
3098
		k++;
3149
		k++;
3099
		LOGICAL(ind)[imin] = 1;
3150
		LOGICAL(ind)[imin] = 1;
3100
 
3151
 
3101
		xi = REAL(x)[imin];
3152
		xi = REAL(x)[imin];
3102
		yi = REAL(y)[imin];
3153
		yi = REAL(y)[imin];
3103
		GConvert(&xi, &yi, USER, INCHES, dd);
3154
		GConvert(&xi, &yi, USER, INCHES, dd);
3104
		if (fabs(xp-xi) >= fabs(yp-yi)) {
3155
		if (fabs(xp-xi) >= fabs(yp-yi)) {
3105
		    if (xp >= xi) {
3156
		    if (xp >= xi) {
3106
			INTEGER(pos)[imin] = 4;
3157
			INTEGER(pos)[imin] = 4;
3107
		    }
3158
		    }
3108
		    else {
3159
		    else {
3109
			INTEGER(pos)[imin] = 2;
3160
			INTEGER(pos)[imin] = 2;
3110
		    }
3161
		    }
3111
		}
3162
		}
3112
		else {
3163
		else {
3113
		    if (yp >= yi) {
3164
		    if (yp >= yi) {
3114
			INTEGER(pos)[imin] = 3;
3165
			INTEGER(pos)[imin] = 3;
3115
		    }
3166
		    }
3116
		    else {
3167
		    else {
3117
			INTEGER(pos)[imin] = 1;
3168
			INTEGER(pos)[imin] = 1;
3118
		    }
3169
		    }
3119
		}
3170
		}
3120
		if (plot)
3171
		if (plot)
3121
		    drawLabel(xi, yi, INTEGER(pos)[imin], offset,
3172
		    drawLabel(xi, yi, INTEGER(pos)[imin], offset,
3122
			      CHAR(STRING_ELT(l, imin)), dd);
3173
			      CHAR(STRING_ELT(l, imin)), dd);
3123
	    }
3174
	    }
3124
	}
3175
	}
3125
	GMode(0, dd);
3176
	GMode(0, dd);
3126
	PROTECT(ans = allocList(2));
3177
	PROTECT(ans = allocList(2));
3127
	SETCAR(ans, ind);
3178
	SETCAR(ans, ind);
3128
	SETCADR(ans, pos);
3179
	SETCADR(ans, pos);
3129
	PROTECT(saveans = allocList(7));
3180
	PROTECT(saveans = allocList(7));
3130
	SETCAR(saveans, ind);
3181
	SETCAR(saveans, ind);
3131
	SETCADR(saveans, pos);
3182
	SETCADR(saveans, pos);
3132
	SETCADDR(saveans, x);
3183
	SETCADDR(saveans, x);
3133
	SETCADDDR(saveans, y);
3184
	SETCADDDR(saveans, y);
3134
	SETCAD4R(saveans, Offset);
3185
	SETCAD4R(saveans, Offset);
3135
	SETCAD4R(CDR(saveans), l);
3186
	SETCAD4R(CDR(saveans), l);
3136
	PROTECT(draw = allocVector(LGLSXP, 1));
3187
	PROTECT(draw = allocVector(LGLSXP, 1));
3137
	LOGICAL(draw)[0] = plot;
3188
	LOGICAL(draw)[0] = plot;
3138
	SETCAD4R(CDDR(saveans), draw);
3189
	SETCAD4R(CDDR(saveans), draw);
3139
 
3190
 
3140
	/* If we are recording, save enough information to be able to
3191
	/* If we are recording, save enough information to be able to
3141
	   redraw the text labels beside identified points */
3192
	   redraw the text labels beside identified points */
3142
	if (GRecording(call))
3193
	if (GRecording(call))
3143
	    recordGraphicOperation(op, saveans, dd);
3194
	    recordGraphicOperation(op, saveans, dd);
3144
	UNPROTECT(5);
3195
	UNPROTECT(5);
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;
3250
static double dnd_offset;
3261
static double dnd_offset;
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;
3281
    xx[1] = xl; yy[1] = *y;
3299
    xx[1] = xl; yy[1] = *y;
3282
    xx[2] = xr; yy[2] = *y;
3300
    xx[2] = xr; yy[2] = *y;
3283
    xx[3] = xr; yy[3] = yr;
3301
    xx[3] = xr; yy[3] = yr;
3284
    GPolyline(4, xx, yy, USER, dd);
3302
    GPolyline(4, xx, yy, USER, dd);
3285
    *x = 0.5 * (xl + xr);
3303
    *x = 0.5 * (xl + xr);
3286
}
3304
}
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);
3335
    ProcessInlinePars(args, dd, call);
3361
    ProcessInlinePars(args, dd, call);
3336
    Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * Rf_gpptr(dd)->cex;
3362
    Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * Rf_gpptr(dd)->cex;
3337
    dnd_offset = GConvertYUnits(GStrWidth("m", INCHES, dd), INCHES, USER, dd);
3363
    dnd_offset = GConvertYUnits(GStrWidth("m", INCHES, dd), INCHES, USER, dd);
3338
 
3364
 
3339
    /* override par("xpd") and force clipping to figure region */
3365
    /* override par("xpd") and force clipping to figure region */
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);
3351
    return R_NilValue;
3377
    return R_NilValue;
3352
 
3378
 
3353
  badargs:
3379
  badargs:
3354
    error("invalid dendrogram input");
3380
    error("invalid dendrogram input");
3355
    return R_NilValue;/* never used; to keep -Wall happy */
3381
    return R_NilValue;/* never used; to keep -Wall happy */
3356
}
3382
}
3357
 
3383
 
3358
SEXP do_dendwindow(SEXP call, SEXP op, SEXP args, SEXP env)
3384
SEXP do_dendwindow(SEXP call, SEXP op, SEXP args, SEXP env)
3359
{
3385
{
3360
    int i, imax, n;
3386
    int i, imax, n;
3361
    double pin, *ll, tmp, yval, *y, ymin, ymax, yrange, m;
3387
    double pin, *ll, tmp, yval, *y, ymin, ymax, yrange, m;
3362
    SEXP originalArgs, merge, height, llabels, str;
3388
    SEXP originalArgs, merge, height, llabels, str;
3363
    char *vmax;
3389
    char *vmax;
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);
3400
    vmax = vmaxget();
3425
    vmax = vmaxget();
3401
    y =  (double*)R_alloc(n, sizeof(double));
3426
    y =  (double*)R_alloc(n, sizeof(double));
3402
    ll = (double*)R_alloc(n, sizeof(double));
3427
    ll = (double*)R_alloc(n, sizeof(double));
3403
    dnd_lptr = &(INTEGER(merge)[0]);
3428
    dnd_lptr = &(INTEGER(merge)[0]);
3404
    dnd_rptr = &(INTEGER(merge)[n]);
3429
    dnd_rptr = &(INTEGER(merge)[n]);
3405
    ymax = ymin = REAL(height)[0];
3430
    ymax = ymin = REAL(height)[0];
3406
    for (i = 1; i < n; i++) {
3431
    for (i = 1; i < n; i++) {
3407
	m = REAL(height)[i];
3432
	m = REAL(height)[i];
3408
	if (m > ymax)
3433
	if (m > ymax)
3409
	    ymax = m;
3434
	    ymax = m;
3410
	else if (m < ymin)
3435
	else if (m < ymin)
3411
	    ymin = m;
3436
	    ymin = m;
3412
    }
3437
    }
3413
    pin = Rf_gpptr(dd)->pin[1];
3438
    pin = Rf_gpptr(dd)->pin[1];
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++) {
3424
	    if (dnd_lptr[i] < 0)
3451
	    if (dnd_lptr[i] < 0)
3425
		y[-dnd_lptr[i] - 1] = REAL(height)[i];
3452
		y[-dnd_lptr[i] - 1] = REAL(height)[i];
3426
	    if (dnd_rptr[i] < 0)
3453
	    if (dnd_rptr[i] < 0)
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);
3464
    vmaxset(vmax);
3486
    vmaxset(vmax);
3465
    return R_NilValue;
3487
    return R_NilValue;
3466
  badargs:
3488
  badargs:
3467
    error("invalid dendrogram input");
3489
    error("invalid dendrogram input");
3468
    return R_NilValue;/* never used; to keep -Wall happy */
3490
    return R_NilValue;/* never used; to keep -Wall happy */
3469
}
3491
}
3470
 
3492
 
3471
 
3493
 
3472
SEXP do_erase(SEXP call, SEXP op, SEXP args, SEXP env)
3494
SEXP do_erase(SEXP call, SEXP op, SEXP args, SEXP env)
3473
{
3495
{
3474
    SEXP col;
3496
    SEXP col;
3475
    int ncol;
3497
    int ncol;
3476
    DevDesc *dd = CurrentDevice();
3498
    DevDesc *dd = CurrentDevice();
3477
    checkArity(op, args);
3499
    checkArity(op, args);
3478
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));
3500
    PROTECT(col = FixupCol(CAR(args), NA_INTEGER));
3479
    ncol = LENGTH(col);
3501
    ncol = LENGTH(col);
3480
    GSavePars(dd);
3502
    GSavePars(dd);
3481
    GMode(1, dd);
3503
    GMode(1, dd);
3482
    GRect(0.0, 0.0, 1.0, 1.0, NDC, INTEGER(col)[0], NA_INTEGER, dd);
3504
    GRect(0.0, 0.0, 1.0, 1.0, NDC, INTEGER(col)[0], NA_INTEGER, dd);
3483
    GMode(0, dd);
3505
    GMode(0, dd);
3484
    GRestorePars(dd);
3506
    GRestorePars(dd);
3485
    UNPROTECT(1);
3507
    UNPROTECT(1);
3486
    return R_NilValue;
3508
    return R_NilValue;
3487
}
3509
}
3488
 
3510
 
3489
 
3511
 
3490
SEXP do_getSnapshot(SEXP call, SEXP op, SEXP args, SEXP env)
3512
SEXP do_getSnapshot(SEXP call, SEXP op, SEXP args, SEXP env)
3491
{
3513
{
3492
    DevDesc *dd = CurrentDevice();
3514
    DevDesc *dd = CurrentDevice();
3493
 
3515
 
3494
    checkArity(op, args);
3516
    checkArity(op, args);
3495
    if (dd->newDevStruct) {
3517
    if (dd->newDevStruct) {
3496
	return GEcreateSnapshot((GEDevDesc*) dd);
3518
	return GEcreateSnapshot((GEDevDesc*) dd);
3497
    } else {
3519
    } else {
3498
	errorcall(call, "can't take snapshot of old-style device");
3520
	errorcall(call, "can't take snapshot of old-style device");
3499
	return R_NilValue;
3521
	return R_NilValue;
3500
    }
3522
    }
3501
}
3523
}
3502
 
3524
 
3503
SEXP do_playSnapshot(SEXP call, SEXP op, SEXP args, SEXP env)
3525
SEXP do_playSnapshot(SEXP call, SEXP op, SEXP args, SEXP env)
3504
{
3526
{
3505
    DevDesc *dd = CurrentDevice();
3527
    DevDesc *dd = CurrentDevice();
3506
 
3528
 
3507
    checkArity(op, args);
3529
    checkArity(op, args);
3508
    if (dd->newDevStruct)
3530
    if (dd->newDevStruct)
3509
	GEplaySnapshot(CAR(args), (GEDevDesc*) dd);
3531
	GEplaySnapshot(CAR(args), (GEDevDesc*) dd);
3510
    else
3532
    else
3511
	errorcall(call, "can't play snapshot on old-style device");
3533
	errorcall(call, "can't play snapshot on old-style device");
3512
    return R_NilValue;
3534
    return R_NilValue;
3513
}
3535
}
3514
 
3536
 
3515
/* I don't think this gets called in any base R code
3537
/* I don't think this gets called in any base R code
3516
 */
3538
 */
3517
SEXP do_replay(SEXP call, SEXP op, SEXP args, SEXP env)
3539
SEXP do_replay(SEXP call, SEXP op, SEXP args, SEXP env)
3518
{
3540
{
3519
    if (!NoDevices()) {
3541
    if (!NoDevices()) {
3520
	GEDevDesc *dd = GEcurrentDevice();
3542
	GEDevDesc *dd = GEcurrentDevice();
3521
	checkArity(op, args);
3543
	checkArity(op, args);
3522
	/*     Rf_dpptr(dd)->resize(); */
3544
	/*     Rf_dpptr(dd)->resize(); */
3523
	GEplayDisplayList(dd);
3545
	GEplayDisplayList(dd);
3524
    }
3546
    }
3525
    return R_NilValue;
3547
    return R_NilValue;
3526
}
3548
}
3527
 
3549
 
3528
SEXP do_playDL(SEXP call, SEXP op, SEXP args, SEXP env)
3550
SEXP do_playDL(SEXP call, SEXP op, SEXP args, SEXP env)
3529
{
3551
{
3530
    DevDesc *dd = CurrentDevice();
3552
    DevDesc *dd = CurrentDevice();
3531
    SEXP theList;
3553
    SEXP theList;
3532
    int ask;
3554
    int ask;
3533
 
3555
 
3534
    checkArity(op, args);
3556
    checkArity(op, args);
3535
    if(!isList(theList = CAR(args)))
3557
    if(!isList(theList = CAR(args)))
3536
       errorcall(call, "invalid argument");
3558
       errorcall(call, "invalid argument");
3537
    if (dd->newDevStruct)
3559
    if (dd->newDevStruct)
3538
	((GEDevDesc*) dd)->dev->displayList = theList;
3560
	((GEDevDesc*) dd)->dev->displayList = theList;
3539
    else
3561
    else
3540
	dd->displayList = theList;
3562
	dd->displayList = theList;
3541
    if (theList != R_NilValue) {
3563
    if (theList != R_NilValue) {
3542
	ask = Rf_gpptr(dd)->ask;
3564
	ask = Rf_gpptr(dd)->ask;
3543
	Rf_gpptr(dd)->ask = 1;
3565
	Rf_gpptr(dd)->ask = 1;
3544
	GReset(dd);
3566
	GReset(dd);
3545
	while (theList != R_NilValue) {
3567
	while (theList != R_NilValue) {
3546
	    SEXP theOperation = CAR(theList);
3568
	    SEXP theOperation = CAR(theList);
3547
	    SEXP l_op = CAR(theOperation);
3569
	    SEXP l_op = CAR(theOperation);
3548
	    SEXP l_args = CDR(theOperation);
3570
	    SEXP l_args = CDR(theOperation);
3549
	    PRIMFUN(l_op) (R_NilValue, l_op, l_args, R_NilValue);
3571
	    PRIMFUN(l_op) (R_NilValue, l_op, l_args, R_NilValue);
3550
	    if (!Rf_gpptr(dd)->valid) break;
3572
	    if (!Rf_gpptr(dd)->valid) break;
3551
	    theList = CDR(theList);
3573
	    theList = CDR(theList);
3552
	}
3574
	}
3553
	Rf_gpptr(dd)->ask = ask;
3575
	Rf_gpptr(dd)->ask = ask;
3554
    }
3576
    }
3555
    return R_NilValue;
3577
    return R_NilValue;
3556
}
3578
}
3557
 
3579
 
3558
SEXP do_setGPar(SEXP call, SEXP op, SEXP args, SEXP env)
3580
SEXP do_setGPar(SEXP call, SEXP op, SEXP args, SEXP env)
3559
{
3581
{
3560
    DevDesc *dd = CurrentDevice();
3582
    DevDesc *dd = CurrentDevice();
3561
    int lGPar = 1 + sizeof(GPar) / sizeof(int);
3583
    int lGPar = 1 + sizeof(GPar) / sizeof(int);
3562
    SEXP GP;
3584
    SEXP GP;
3563
 
3585
 
3564
    checkArity(op, args);
3586
    checkArity(op, args);
3565
    GP = CAR(args);
3587
    GP = CAR(args);
3566
    if (!isInteger(GP) || length(GP) != lGPar)
3588
    if (!isInteger(GP) || length(GP) != lGPar)
3567
	errorcall(call, "invalid graphics parameter list");
3589
	errorcall(call, "invalid graphics parameter list");
3568
    copyGPar((GPar *) INTEGER(GP), Rf_dpSavedptr(dd)); /* &dd->Rf_dpSaved); */
3590
    copyGPar((GPar *) INTEGER(GP), Rf_dpSavedptr(dd)); /* &dd->Rf_dpSaved); */
3569
    return R_NilValue;
3591
    return R_NilValue;
3570
}
3592
}
3571
 
3593
 
3572
/* symbols(..) in ../library/base/R/symbols.R  : */
3594
/* symbols(..) in ../library/base/R/symbols.R  : */
3573
 
3595
 
3574
/* utility just computing range() */
3596
/* utility just computing range() */
3575
static Rboolean SymbolRange(double *x, int n, double *xmax, double *xmin)
3597
static Rboolean SymbolRange(double *x, int n, double *xmax, double *xmin)
3576
{
3598
{
3577
    int i;
3599
    int i;
3578
    *xmax = -DBL_MAX;
3600
    *xmax = -DBL_MAX;
3579
    *xmin =  DBL_MAX;
3601
    *xmin =  DBL_MAX;
3580
    for(i = 0; i < n; i++)
3602
    for(i = 0; i < n; i++)
3581
	if (R_FINITE(x[i])) {
3603
	if (R_FINITE(x[i])) {
3582
	    if (*xmax < x[i]) *xmax = x[i];
3604
	    if (*xmax < x[i]) *xmax = x[i];
3583
	    if (*xmin > x[i]) *xmin = x[i];
3605
	    if (*xmin > x[i]) *xmin = x[i];
3584
	}
3606
	}
3585
    return(*xmax >= *xmin && *xmin >= 0);
3607
    return(*xmax >= *xmin && *xmin >= 0);
3586
}
3608
}
3587
 
3609
 
3588
static void CheckSymbolPar(SEXP call, SEXP p, int *nr, int *nc)
3610
static void CheckSymbolPar(SEXP call, SEXP p, int *nr, int *nc)
3589
{
3611
{
3590
    SEXP dim = getAttrib(p, R_DimSymbol);
3612
    SEXP dim = getAttrib(p, R_DimSymbol);
3591
    switch(length(dim)) {
3613
    switch(length(dim)) {
3592
    case 0:
3614
    case 0:
3593
	*nr = LENGTH(p);
3615
	*nr = LENGTH(p);
3594
	*nc = 1;
3616
	*nc = 1;
3595
	break;
3617
	break;
3596
    case 1:
3618
    case 1:
3597
	*nr = INTEGER(dim)[0];
3619
	*nr = INTEGER(dim)[0];
3598
	*nc = 1;
3620
	*nc = 1;
3599
	break;
3621
	break;
3600
    case 2:
3622
    case 2:
3601
	*nr = INTEGER(dim)[0];
3623
	*nr = INTEGER(dim)[0];
3602
	*nc = INTEGER(dim)[1];
3624
	*nc = INTEGER(dim)[1];
3603
	break;
3625
	break;
3604
    default:
3626
    default:
3605
	*nr = 0;
3627
	*nr = 0;
3606
	*nc = 0;
3628
	*nc = 0;
3607
    }
3629
    }
3608
    if (*nr == 0 || *nc == 0)
3630
    if (*nr == 0 || *nc == 0)
3609
	errorcall(call, "invalid symbol parameter vector");
3631
	errorcall(call, "invalid symbol parameter vector");
3610
}
3632
}
3611
 
3633
 
3612
/* Internal  symbols(x, y, type, data, inches, bg, fg, ...) */
3634
/* Internal  symbols(x, y, type, data, inches, bg, fg, ...) */
3613
SEXP do_symbols(SEXP call, SEXP op, SEXP args, SEXP env)
3635
SEXP do_symbols(SEXP call, SEXP op, SEXP args, SEXP env)
3614
{
3636
{
3615
    SEXP x, y, p, fg, bg;
3637
    SEXP x, y, p, fg, bg;
3616
    int i, j, nr, nc, nbg, nfg, type;
3638
    int i, j, nr, nc, nbg, nfg, type;
3617
    double pmax, pmin, inches, rx, ry;
3639
    double pmax, pmin, inches, rx, ry;
3618
    double xx, yy, p0, p1, p2, p3, p4;
3640
    double xx, yy, p0, p1, p2, p3, p4;
3619
    double *pp, *xp, *yp;
3641
    double *pp, *xp, *yp;
3620
    char *vmax;
3642
    char *vmax;
3621
 
3643
 
3622
    SEXP originalArgs = args;
3644
    SEXP originalArgs = args;
3623
    DevDesc *dd = CurrentDevice();
3645
    DevDesc *dd = CurrentDevice();
3624
    GCheckState(dd);
3646
    GCheckState(dd);
3625
 
3647
 
3626
    if (length(args) < 7)
3648
    if (length(args) < 7)
3627
	errorcall(call, "insufficient arguments");
3649
	errorcall(call, "insufficient arguments");
3628
 
3650
 
3629
    PROTECT(x = coerceVector(CAR(args), REALSXP)); args = CDR(args);
3651
    PROTECT(x = coerceVector(CAR(args), REALSXP)); args = CDR(args);
3630
    PROTECT(y = coerceVector(CAR(args), REALSXP)); args = CDR(args);
3652
    PROTECT(y = coerceVector(CAR(args), REALSXP)); args = CDR(args);
3631
    if (!isNumeric(x) || !isNumeric(y) || length(x) <= 0 || LENGTH(x) <= 0)
3653
    if (!isNumeric(x) || !isNumeric(y) || length(x) <= 0 || LENGTH(x) <= 0)
3632
	errorcall(call, "invalid symbol coordinates");
3654
	errorcall(call, "invalid symbol coordinates");
3633
 
3655
 
3634
    type = asInteger(CAR(args)); args = CDR(args);
3656
    type = asInteger(CAR(args)); args = CDR(args);
3635
 
3657
 
3636
    /* data: */
3658
    /* data: */
3637
    p = PROTECT(coerceVector(CAR(args), REALSXP)); args = CDR(args);
3659
    p = PROTECT(coerceVector(CAR(args), REALSXP)); args = CDR(args);
3638
    CheckSymbolPar(call, p, &nr, &nc);
3660
    CheckSymbolPar(call, p, &nr, &nc);
3639
    if (LENGTH(x) != nr || LENGTH(y) != nr)
3661
    if (LENGTH(x) != nr || LENGTH(y) != nr)
3640
	errorcall(call, "x/y/parameter length mismatch");
3662
	errorcall(call, "x/y/parameter length mismatch");
3641
 
3663
 
3642
    inches = asReal(CAR(args)); args = CDR(args);
3664
    inches = asReal(CAR(args)); args = CDR(args);
3643
    if (!R_FINITE(inches) || inches < 0)
3665
    if (!R_FINITE(inches) || inches < 0)
3644
	inches = 0;
3666
	inches = 0;
3645
 
3667
 
3646
    PROTECT(bg = FixupCol(CAR(args), NA_INTEGER)); args = CDR(args);
3668
    PROTECT(bg = FixupCol(CAR(args), NA_INTEGER)); args = CDR(args);
3647
    nbg = LENGTH(bg);
3669
    nbg = LENGTH(bg);
3648
 
3670
 
3649
    PROTECT(fg = FixupCol(CAR(args), NA_INTEGER)); args = CDR(args);
3671
    PROTECT(fg = FixupCol(CAR(args), NA_INTEGER)); args = CDR(args);
3650
    nfg = LENGTH(fg);
3672
    nfg = LENGTH(fg);
3651
 
3673
 
3652
    GSavePars(dd);
3674
    GSavePars(dd);
3653
    ProcessInlinePars(args, dd, call);
3675
    ProcessInlinePars(args, dd, call);
3654
 
3676
 
3655
    GMode(1, dd);
3677
    GMode(1, dd);
3656
    switch (type) {
3678
    switch (type) {
3657
    case 1: /* circles */
3679
    case 1: /* circles */
3658
	if (nc != 1)
3680
	if (nc != 1)
3659
	    errorcall(call, "invalid circles data");
3681
	    errorcall(call, "invalid circles data");
3660
	if (!SymbolRange(REAL(p), nr, &pmax, &pmin))
3682
	if (!SymbolRange(REAL(p), nr, &pmax, &pmin))
3661
	    errorcall(call, "invalid symbol parameter");
3683
	    errorcall(call, "invalid symbol parameter");
3662
	for (i = 0; i < nr; i++) {
3684
	for (i = 0; i < nr; i++) {
3663
	    if (R_FINITE(REAL(x)[i]) && R_FINITE(REAL(y)[i]) &&
3685
	    if (R_FINITE(REAL(x)[i]) && R_FINITE(REAL(y)[i]) &&
3664
		R_FINITE(REAL(p)[i])) {
3686
		R_FINITE(REAL(p)[i])) {
3665
		rx = REAL(p)[i];
3687
		rx = REAL(p)[i];
3666
		if (inches > 0)
3688
		if (inches > 0)
3667
		    rx *= inches / pmax;/* <-- no GConvert ?? */
3689
		    rx *= inches / pmax;/* <-- no GConvert ?? */
3668
		else/* FIXME : INCHES in the following ??? */
3690
		else/* FIXME : INCHES in the following ??? */
3669
		    rx = GConvertXUnits(rx, USER, INCHES, dd);
3691
		    rx = GConvertXUnits(rx, USER, INCHES, dd);
3670
		GCircle(REAL(x)[i], REAL(y)[i],	USER, rx,
3692
		GCircle(REAL(x)[i], REAL(y)[i],	USER, rx,
3671
			INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg],	dd);
3693
			INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg],	dd);
3672
	    }
3694
	    }
3673
	}
3695
	}
3674
	break;
3696
	break;
3675
    case 2: /* squares */
3697
    case 2: /* squares */
3676
	if(nc != 1)
3698
	if(nc != 1)
3677
	    errorcall(call, "invalid squares data");
3699
	    errorcall(call, "invalid squares data");
3678
	if(!SymbolRange(REAL(p), nr, &pmax, &pmin))
3700
	if(!SymbolRange(REAL(p), nr, &pmax, &pmin))
3679
	    errorcall(call, "invalid symbol parameter");
3701
	    errorcall(call, "invalid symbol parameter");
3680
	for (i = 0; i < nr; i++) {
3702
	for (i = 0; i < nr; i++) {
3681
	    if (R_FINITE(REAL(x)[i]) && R_FINITE(REAL(y)[i]) &&
3703
	    if (R_FINITE(REAL(x)[i]) && R_FINITE(REAL(y)[i]) &&
3682
		R_FINITE(REAL(p)[i])) {
3704
		R_FINITE(REAL(p)[i])) {
3683
		p0 = REAL(p)[i];
3705
		p0 = REAL(p)[i];
3684
		xx = REAL(x)[i];
3706
		xx = REAL(x)[i];
3685
		yy = REAL(y)[i];
3707
		yy = REAL(y)[i];
3686
		GConvert(&xx, &yy, USER, DEVICE, dd);
3708
		GConvert(&xx, &yy, USER, DEVICE, dd);
3687
		if (inches > 0) {
3709
		if (inches > 0) {
3688
		    p0 = p0 / pmax * inches;
3710
		    p0 = p0 / pmax * inches;
3689
		    rx = GConvertXUnits(0.5 * p0, INCHES, DEVICE, dd);
3711
		    rx = GConvertXUnits(0.5 * p0, INCHES, DEVICE, dd);
3690
		    ry = GConvertYUnits(0.5 * p0, INCHES, DEVICE, dd);
3712
		    ry = GConvertYUnits(0.5 * p0, INCHES, DEVICE, dd);
3691
		}
3713
		}
3692
		else {
3714
		else {
3693
		    rx = GConvertXUnits(0.5 * p0, USER, DEVICE, dd);
3715
		    rx = GConvertXUnits(0.5 * p0, USER, DEVICE, dd);
3694
		    ry = GConvertYUnits(0.5 * p0, USER, DEVICE, dd);
3716
		    ry = GConvertYUnits(0.5 * p0, USER, DEVICE, dd);
3695
		}
3717
		}
3696
		GRect(xx - rx, yy - rx, xx + rx, yy + rx, DEVICE,
3718
		GRect(xx - rx, yy - rx, xx + rx, yy + rx, DEVICE,
3697
		      INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg], dd);
3719
		      INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg], dd);
3698
	    }
3720
	    }
3699
	}
3721
	}
3700
	break;
3722
	break;
3701
    case 3: /* rectangles */
3723
    case 3: /* rectangles */
3702
	if (nc != 2)
3724
	if (nc != 2)
3703
	    errorcall(call, "invalid rectangles data (need 2 columns)");
3725
	    errorcall(call, "invalid rectangles data (need 2 columns)");
3704
	if (!SymbolRange(REAL(p), 2 * nr, &pmax, &pmin))
3726
	if (!SymbolRange(REAL(p), 2 * nr, &pmax, &pmin))
3705
	    errorcall(call, "invalid symbol parameter");
3727
	    errorcall(call, "invalid symbol parameter");
3706
	for (i = 0; i < nr; i++) {
3728
	for (i = 0; i < nr; i++) {
3707
	    if (R_FINITE(REAL(x)[i]) && R_FINITE(REAL(y)[i]) &&
3729
	    if (R_FINITE(REAL(x)[i]) && R_FINITE(REAL(y)[i]) &&
3708
		R_FINITE(REAL(p)[i]) && R_FINITE(REAL(p)[i+nr])) {
3730
		R_FINITE(REAL(p)[i]) && R_FINITE(REAL(p)[i+nr])) {
3709
		xx = REAL(x)[i];
3731
		xx = REAL(x)[i];
3710
		yy = REAL(y)[i];
3732
		yy = REAL(y)[i];
3711
		GConvert(&xx, &yy, USER, DEVICE, dd);
3733
		GConvert(&xx, &yy, USER, DEVICE, dd);
3712
		p0 = REAL(p)[i];
3734
		p0 = REAL(p)[i];
3713
		p1 = REAL(p)[i+nr];
3735
		p1 = REAL(p)[i+nr];
3714
		if (inches > 0) {
3736
		if (inches > 0) {
3715
		    p0 *= inches / pmax;
3737
		    p0 *= inches / pmax;
3716
		    p1 *= inches / pmax;
3738
		    p1 *= inches / pmax;
3717
		    rx = GConvertXUnits(0.5 * p0, INCHES, DEVICE, dd);
3739
		    rx = GConvertXUnits(0.5 * p0, INCHES, DEVICE, dd);
3718
		    ry = GConvertYUnits(0.5 * p1, INCHES, DEVICE, dd);
3740
		    ry = GConvertYUnits(0.5 * p1, INCHES, DEVICE, dd);
3719
		}
3741
		}
3720
		else {
3742
		else {
3721
		    rx = GConvertXUnits(0.5 * p0, USER, DEVICE, dd);
3743
		    rx = GConvertXUnits(0.5 * p0, USER, DEVICE, dd);
3722
		    ry = GConvertYUnits(0.5 * p1, USER, DEVICE, dd);
3744
		    ry = GConvertYUnits(0.5 * p1, USER, DEVICE, dd);
3723
		}
3745
		}
3724
		GRect(xx - rx, yy - ry, xx + rx, yy + ry, DEVICE,
3746
		GRect(xx - rx, yy - ry, xx + rx, yy + ry, DEVICE,
3725
		      INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg], dd);
3747
		      INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg], dd);
3726
 
3748
 
3727
	    }
3749
	    }
3728
	}
3750
	}
3729
	break;
3751
	break;
3730
    case 4: /* stars */
3752
    case 4: /* stars */
3731
	if (nc < 3)
3753
	if (nc < 3)
3732
	    errorcall(call, "invalid stars data");
3754
	    errorcall(call, "invalid stars data");
3733
	if (!SymbolRange(REAL(p), nc * nr, &pmax, &pmin))
3755
	if (!SymbolRange(REAL(p), nc * nr, &pmax, &pmin))
3734
	    errorcall(call, "invalid symbol parameter");
3756
	    errorcall(call, "invalid symbol parameter");
3735
	vmax = vmaxget();
3757
	vmax = vmaxget();
3736
	pp = (double*)R_alloc(nc, sizeof(double));
3758
	pp = (double*)R_alloc(nc, sizeof(double));
3737
	xp = (double*)R_alloc(nc, sizeof(double));
3759
	xp = (double*)R_alloc(nc, sizeof(double));
3738
	yp = (double*)R_alloc(nc, sizeof(double));
3760
	yp = (double*)R_alloc(nc, sizeof(double));
3739
	p1 = 2.0 * M_PI / nc;
3761
	p1 = 2.0 * M_PI / nc;
3740
	for (i = 0; i < nr; i++) {
3762
	for (i = 0; i < nr; i++) {
3741
	    xx = REAL(x)[i];
3763
	    xx = REAL(x)[i];
3742
	    yy = REAL(y)[i];
3764
	    yy = REAL(y)[i];
3743
	    if (R_FINITE(xx) && R_FINITE(yy)) {
3765
	    if (R_FINITE(xx) && R_FINITE(yy)) {
3744
		GConvert(&xx, &yy, USER, NDC, dd);
3766
		GConvert(&xx, &yy, USER, NDC, dd);
3745
		if (inches > 0) {
3767
		if (inches > 0) {
3746
		    for(j = 0; j < nc; j++) {
3768
		    for(j = 0; j < nc; j++) {
3747
			p0 = REAL(p)[i + j * nr];
3769
			p0 = REAL(p)[i + j * nr];
3748
			if (!R_FINITE(p0)) p0 = 0;
3770
			if (!R_FINITE(p0)) p0 = 0;
3749
			pp[j] = (p0 / pmax) * inches;
3771
			pp[j] = (p0 / pmax) * inches;
3750
		    }
3772
		    }
3751
		}
3773
		}
3752
		else {
3774
		else {
3753
		    for(j = 0; j < nc; j++) {
3775
		    for(j = 0; j < nc; j++) {
3754
			p0 = REAL(p)[i + j * nr];
3776
			p0 = REAL(p)[i + j * nr];
3755
			if (!R_FINITE(p0)) p0 = 0;
3777
			if (!R_FINITE(p0)) p0 = 0;
3756
			pp[j] =	 GConvertXUnits(p0, USER, INCHES, dd);
3778
			pp[j] =	 GConvertXUnits(p0, USER, INCHES, dd);
3757
		    }
3779
		    }
3758
		}
3780
		}
3759
		for(j = 0; j < nc; j++) {
3781
		for(j = 0; j < nc; j++) {
3760
		    xp[j] = GConvertXUnits(pp[j] * cos(j * p1),
3782
		    xp[j] = GConvertXUnits(pp[j] * cos(j * p1),
3761
					   INCHES, NDC, dd) + xx;
3783
					   INCHES, NDC, dd) + xx;
3762
		    yp[j] = GConvertYUnits(pp[j] * sin(j * p1),
3784
		    yp[j] = GConvertYUnits(pp[j] * sin(j * p1),
3763
					   INCHES, NDC, dd) + yy;
3785
					   INCHES, NDC, dd) + yy;
3764
		}
3786
		}
3765
		GPolygon(nc, xp, yp, NDC,
3787
		GPolygon(nc, xp, yp, NDC,
3766
			 INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg], dd);
3788
			 INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg], dd);
3767
	    }
3789
	    }
3768
	}
3790
	}
3769
	vmaxset(vmax);
3791
	vmaxset(vmax);
3770
	break;
3792
	break;
3771
    case 5: /* thermometers */
3793
    case 5: /* thermometers */
3772
	if (nc != 3 && nc != 4)
3794
	if (nc != 3 && nc != 4)
3773
	    errorcall(call, "invalid thermometers data (need 3 or 4 columns)");
3795
	    errorcall(call, "invalid thermometers data (need 3 or 4 columns)");
3774
	SymbolRange(REAL(p)+2*nr/* <-- pointer arith*/, nr, &pmax, &pmin);
3796
	SymbolRange(REAL(p)+2*nr/* <-- pointer arith*/, nr, &pmax, &pmin);
3775
	if (pmax < pmin)
3797
	if (pmax < pmin)
3776
	    errorcall(call, "invalid thermometers[,%s]",(nc == 4)? "3:4" : "3");
3798
	    errorcall(call, "invalid thermometers[,%s]",(nc == 4)? "3:4" : "3");
3777
	if (pmin < 0. || pmax > 1.) /* S-PLUS has an error here */
3799
	if (pmin < 0. || pmax > 1.) /* S-PLUS has an error here */
3778
	    warningcall(call,"thermometers[,%s] not in [0,1] -- may look funny",
3800
	    warningcall(call,"thermometers[,%s] not in [0,1] -- may look funny",
3779
			(nc == 4)? "3:4" : "3");
3801
			(nc == 4)? "3:4" : "3");
3780
	if (!SymbolRange(REAL(p), 2 * nr, &pmax, &pmin))
3802
	if (!SymbolRange(REAL(p), 2 * nr, &pmax, &pmin))
3781
	    errorcall(call, "invalid thermometers[,1:2]");
3803
	    errorcall(call, "invalid thermometers[,1:2]");
3782
	for (i = 0; i < nr; i++) {
3804
	for (i = 0; i < nr; i++) {
3783
	    xx = REAL(x)[i];
3805
	    xx = REAL(x)[i];
3784
	    yy = REAL(y)[i];
3806
	    yy = REAL(y)[i];
3785
	    if (R_FINITE(xx) && R_FINITE(yy)) {
3807
	    if (R_FINITE(xx) && R_FINITE(yy)) {
3786
		p0 = REAL(p)[i];
3808
		p0 = REAL(p)[i];
3787
		p1 = REAL(p)[i + nr];
3809
		p1 = REAL(p)[i + nr];
3788
		p2 = REAL(p)[i + 2 * nr];
3810
		p2 = REAL(p)[i + 2 * nr];
3789
		p3 = (nc == 4)? REAL(p)[i + 3 * nr] : 0.;
3811
		p3 = (nc == 4)? REAL(p)[i + 3 * nr] : 0.;
3790
		if (R_FINITE(p0) && R_FINITE(p1) &&
3812
		if (R_FINITE(p0) && R_FINITE(p1) &&
3791
		    R_FINITE(p2) && R_FINITE(p3)) {
3813
		    R_FINITE(p2) && R_FINITE(p3)) {
3792
		    if (p2 < 0) p2 = 0; else if (p2 > 1) p2 = 1;
3814
		    if (p2 < 0) p2 = 0; else if (p2 > 1) p2 = 1;
3793
		    if (p3 < 0) p3 = 0; else if (p3 > 1) p3 = 1;
3815
		    if (p3 < 0) p3 = 0; else if (p3 > 1) p3 = 1;
3794
		    GConvert(&xx, &yy, USER, NDC, dd);
3816
		    GConvert(&xx, &yy, USER, NDC, dd);
3795
		    if (inches > 0) {
3817
		    if (inches > 0) {
3796
			p0 *= inches / pmax;
3818
			p0 *= inches / pmax;
3797
			p1 *= inches / pmax;
3819
			p1 *= inches / pmax;
3798
			rx = GConvertXUnits(0.5 * p0, INCHES, NDC, dd);
3820
			rx = GConvertXUnits(0.5 * p0, INCHES, NDC, dd);
3799
			ry = GConvertYUnits(0.5 * p1, INCHES, NDC, dd);
3821
			ry = GConvertYUnits(0.5 * p1, INCHES, NDC, dd);
3800
		    }
3822
		    }
3801
		    else {
3823
		    else {
3802
			rx = GConvertXUnits(0.5 * p0, USER, NDC, dd);
3824
			rx = GConvertXUnits(0.5 * p0, USER, NDC, dd);
3803
			ry = GConvertYUnits(0.5 * p1, USER, NDC, dd);
3825
			ry = GConvertYUnits(0.5 * p1, USER, NDC, dd);
3804
		    }
3826
		    }
3805
		    GRect(xx - rx, yy - ry, xx + rx, yy + ry, NDC,
3827
		    GRect(xx - rx, yy - ry, xx + rx, yy + ry, NDC,
3806
			  INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg], dd);
3828
			  INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg], dd);
3807
		    GRect(xx - rx,  yy - (1 - 2 * p2) * ry,
3829
		    GRect(xx - rx,  yy - (1 - 2 * p2) * ry,
3808
			  xx + rx,  yy - (1 - 2 * p3) * ry,
3830
			  xx + rx,  yy - (1 - 2 * p3) * ry,
3809
			  NDC,
3831
			  NDC,
3810
			  INTEGER(fg)[i%nfg], INTEGER(fg)[i%nfg], dd);
3832
			  INTEGER(fg)[i%nfg], INTEGER(fg)[i%nfg], dd);
3811
		    GLine(xx - rx, yy, xx - 1.5 * rx, yy, NDC, dd);
3833
		    GLine(xx - rx, yy, xx - 1.5 * rx, yy, NDC, dd);
3812
		    GLine(xx + rx, yy, xx + 1.5 * rx, yy, NDC, dd);
3834
		    GLine(xx + rx, yy, xx + 1.5 * rx, yy, NDC, dd);
3813
 
3835
 
3814
		}
3836
		}
3815
	    }
3837
	    }
3816
	}
3838
	}
3817
	break;
3839
	break;
3818
    case 6: /* boxplots (wid, hei, loWhsk, upWhsk, medProp) */
3840
    case 6: /* boxplots (wid, hei, loWhsk, upWhsk, medProp) */
3819
	if (nc != 5)
3841
	if (nc != 5)
3820
	    errorcall(call, "invalid boxplots data (need 5 columns)");
3842
	    errorcall(call, "invalid boxplots data (need 5 columns)");
3821
	pmax = -DBL_MAX;
3843
	pmax = -DBL_MAX;
3822
	pmin =	DBL_MAX;
3844
	pmin =	DBL_MAX;
3823
	for(i = 0; i < nr; i++) {
3845
	for(i = 0; i < nr; i++) {
3824
	    p4 = REAL(p)[i + 4 * nr];	/* median proport. in [0,1] */
3846
	    p4 = REAL(p)[i + 4 * nr];	/* median proport. in [0,1] */
3825
	    if (pmax < p4) pmax = p4;
3847
	    if (pmax < p4) pmax = p4;
3826
	    if (pmin > p4) pmin = p4;
3848
	    if (pmin > p4) pmin = p4;
3827
	}
3849
	}
3828
	if (pmin < 0. || pmax > 1.) /* S-PLUS has an error here */
3850
	if (pmin < 0. || pmax > 1.) /* S-PLUS has an error here */
3829
	    warningcall(call, "boxplots[,5] outside [0,1] -- may look funny");
3851
	    warningcall(call, "boxplots[,5] outside [0,1] -- may look funny");
3830
	if (!SymbolRange(REAL(p), 4 * nr, &pmax, &pmin))
3852
	if (!SymbolRange(REAL(p), 4 * nr, &pmax, &pmin))
3831
	    errorcall(call, "invalid boxplots[, 1:4]");
3853
	    errorcall(call, "invalid boxplots[, 1:4]");
3832
	for (i = 0; i < nr; i++) {
3854
	for (i = 0; i < nr; i++) {
3833
	    xx = REAL(x)[i];
3855
	    xx = REAL(x)[i];
3834
	    yy = REAL(y)[i];
3856
	    yy = REAL(y)[i];
3835
	    if (R_FINITE(xx) && R_FINITE(yy)) {
3857
	    if (R_FINITE(xx) && R_FINITE(yy)) {
3836
		p0 = REAL(p)[i];	/* width */
3858
		p0 = REAL(p)[i];	/* width */
3837
		p1 = REAL(p)[i + nr];	/* height */
3859
		p1 = REAL(p)[i + nr];	/* height */
3838
		p2 = REAL(p)[i + 2 * nr];/* lower whisker */
3860
		p2 = REAL(p)[i + 2 * nr];/* lower whisker */
3839
		p3 = REAL(p)[i + 3 * nr];/* upper whisker */
3861
		p3 = REAL(p)[i + 3 * nr];/* upper whisker */
3840
		p4 = REAL(p)[i + 4 * nr];/* median proport. in [0,1] */
3862
		p4 = REAL(p)[i + 4 * nr];/* median proport. in [0,1] */
3841
		if (R_FINITE(p0) && R_FINITE(p1) &&
3863
		if (R_FINITE(p0) && R_FINITE(p1) &&
3842
		    R_FINITE(p2) && R_FINITE(p3) && R_FINITE(p4)) {
3864
		    R_FINITE(p2) && R_FINITE(p3) && R_FINITE(p4)) {
3843
		    GConvert(&xx, &yy, USER, NDC, dd);
3865
		    GConvert(&xx, &yy, USER, NDC, dd);
3844
		    if (inches > 0) {
3866
		    if (inches > 0) {
3845
			p0 *= inches / pmax;
3867
			p0 *= inches / pmax;
3846
			p1 *= inches / pmax;
3868
			p1 *= inches / pmax;
3847
			p2 *= inches / pmax;
3869
			p2 *= inches / pmax;
3848
			p3 *= inches / pmax;
3870
			p3 *= inches / pmax;
3849
			p0 = GConvertXUnits(p0, INCHES, NDC, dd);
3871
			p0 = GConvertXUnits(p0, INCHES, NDC, dd);
3850
			p1 = GConvertYUnits(p1, INCHES, NDC, dd);
3872
			p1 = GConvertYUnits(p1, INCHES, NDC, dd);
3851
			p2 = GConvertYUnits(p2, INCHES, NDC, dd);
3873
			p2 = GConvertYUnits(p2, INCHES, NDC, dd);
3852
			p3 = GConvertYUnits(p3, INCHES, NDC, dd);
3874
			p3 = GConvertYUnits(p3, INCHES, NDC, dd);
3853
		    }
3875
		    }
3854
		    else {
3876
		    else {
3855
			p0 = GConvertXUnits(p0, USER, NDC, dd);
3877
			p0 = GConvertXUnits(p0, USER, NDC, dd);
3856
			p1 = GConvertYUnits(p1, USER, NDC, dd);
3878
			p1 = GConvertYUnits(p1, USER, NDC, dd);
3857
			p2 = GConvertYUnits(p2, USER, NDC, dd);
3879
			p2 = GConvertYUnits(p2, USER, NDC, dd);
3858
			p3 = GConvertYUnits(p3, USER, NDC, dd);
3880
			p3 = GConvertYUnits(p3, USER, NDC, dd);
3859
		    }
3881
		    }
3860
		    rx = 0.5 * p0;
3882
		    rx = 0.5 * p0;
3861
		    ry = 0.5 * p1;
3883
		    ry = 0.5 * p1;
3862
		    p4 = (1 - p4) * (yy - ry) + p4 * (yy + ry);
3884
		    p4 = (1 - p4) * (yy - ry) + p4 * (yy + ry);
3863
		    /* Box */
3885
		    /* Box */
3864
		    GRect(xx - rx, yy - ry, xx + rx, yy + ry, NDC,
3886
		    GRect(xx - rx, yy - ry, xx + rx, yy + ry, NDC,
3865
			  INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg], dd);
3887
			  INTEGER(bg)[i%nbg], INTEGER(fg)[i%nfg], dd);
3866
		    /* Median */
3888
		    /* Median */
3867
		    GLine(xx - rx, p4, xx + rx, p4, NDC, dd);
3889
		    GLine(xx - rx, p4, xx + rx, p4, NDC, dd);
3868
		    /* Lower Whisker */
3890
		    /* Lower Whisker */
3869
		    GLine(xx, yy - ry, xx, yy - ry - p2, NDC, dd);
3891
		    GLine(xx, yy - ry, xx, yy - ry - p2, NDC, dd);
3870
		    /* Upper Whisker */
3892
		    /* Upper Whisker */
3871
		    GLine(xx, yy + ry, xx, yy + ry + p3, NDC, dd);
3893
		    GLine(xx, yy + ry, xx, yy + ry + p3, NDC, dd);
3872
		}
3894
		}
3873
	    }
3895
	    }
3874
	}
3896
	}
3875
	break;
3897
	break;
3876
    default:
3898
    default:
3877
	errorcall(call, "invalid symbol type");
3899
	errorcall(call, "invalid symbol type");
3878
    }
3900
    }
3879
    GMode(0, dd);
3901
    GMode(0, dd);
3880
    GRestorePars(dd);
3902
    GRestorePars(dd);
3881
    if (GRecording(call))
3903
    if (GRecording(call))
3882
	recordGraphicOperation(op, originalArgs, dd);
3904
	recordGraphicOperation(op, originalArgs, dd);
3883
    UNPROTECT(5);
3905
    UNPROTECT(5);
3884
    return R_NilValue;
3906
    return R_NilValue;
3885
}
3907
}