The R Project SVN R

Rev

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

Rev 41901 Rev 42208
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-2007   Robert Gentleman, Ross Ihaka and the R core team.
4
 *  Copyright (C) 1997-2007   Robert Gentleman, Ross Ihaka and the R core team.
5
 *
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
9
 *  (at your option) any later version.
10
 *
10
 *
11
 *  This program is distributed in the hope that it will be useful,
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
14
 *  GNU General Public License for more details.
15
 *
15
 *
16
 *  You should have received a copy of the GNU General Public License
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, write to the Free Software
17
 *  along with this program; if not, write to the Free Software
18
 *  Foundation, Inc., 51 Franklin Street Fifth Floor, Boston, MA 02110-1301  USA
18
 *  Foundation, Inc., 51 Franklin Street Fifth Floor, Boston, MA 02110-1301  USA
19
 */
19
 */
20
 
20
 
21
/* <UTF8> char here is either ASCII or handled as a whole */
21
/* <UTF8> char here is either ASCII or handled as a whole */
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
#include <R_ext/Boolean.h>
33
#include <R_ext/Boolean.h>
34
 
34
 
35
#ifndef HAVE_HYPOT
35
#ifndef HAVE_HYPOT
36
# define hypot pythag
36
# define hypot pythag
37
#endif
37
#endif
38
 
38
 
39
/* Conversion of degrees to radians */
39
/* Conversion of degrees to radians */
40
 
40
 
41
#define DegToRad(x) (0.01745329251994329576 * x)
41
#define DegToRad(x) (0.01745329251994329576 * x)
42
 
42
 
43
/* Definitions of data structures for vectors and */
43
/* Definitions of data structures for vectors and */
44
/* transformations in homogeneous 3d coordinates */
44
/* transformations in homogeneous 3d coordinates */
45
 
45
 
46
typedef double Vector3d[4];
46
typedef double Vector3d[4];
47
typedef double Trans3d[4][4];
47
typedef double Trans3d[4][4];
48
 
48
 
49
/* The viewing transformation matrix. */
49
/* The viewing transformation matrix. */
50
 
50
 
51
static SEXP gcall;
51
static SEXP gcall;
52
static Trans3d VT;
52
static Trans3d VT;
53
 
53
 
54
static void TransVector (Vector3d u, Trans3d T, Vector3d v)
54
static void TransVector (Vector3d u, Trans3d T, Vector3d v)
55
{
55
{
56
    double sum;
56
    double sum;
57
    int i, j;
57
    int i, j;
58
 
58
 
59
    for (i = 0; i < 4; i++) {
59
    for (i = 0; i < 4; i++) {
60
	sum = 0;
60
	sum = 0;
61
	for (j = 0; j < 4; j++)
61
	for (j = 0; j < 4; j++)
62
	    sum = sum + u[j] * T[j][i];
62
	    sum = sum + u[j] * T[j][i];
63
	v[i] = sum;
63
	v[i] = sum;
64
    }
64
    }
65
}
65
}
66
 
66
 
67
static void Accumulate (Trans3d T)
67
static void Accumulate (Trans3d T)
68
{
68
{
69
    Trans3d U;
69
    Trans3d U;
70
    double sum;
70
    double sum;
71
    int i, j, k;
71
    int i, j, k;
72
 
72
 
73
    for (i = 0; i < 4; i++) {
73
    for (i = 0; i < 4; i++) {
74
	for (j = 0; j < 4; j++) {
74
	for (j = 0; j < 4; j++) {
75
	    sum = 0;
75
	    sum = 0;
76
	    for (k = 0; k < 4; k++)
76
	    for (k = 0; k < 4; k++)
77
		sum = sum + VT[i][k] * T[k][j];
77
		sum = sum + VT[i][k] * T[k][j];
78
	    U[i][j] = sum;
78
	    U[i][j] = sum;
79
	}
79
	}
80
    }
80
    }
81
    for (i = 0; i < 4; i++)
81
    for (i = 0; i < 4; i++)
82
	for (j = 0; j < 4; j++)
82
	for (j = 0; j < 4; j++)
83
	    VT[i][j] = U[i][j];
83
	    VT[i][j] = U[i][j];
84
}
84
}
85
 
85
 
86
static void SetToIdentity (Trans3d T)
86
static void SetToIdentity (Trans3d T)
87
{
87
{
88
    int i, j;
88
    int i, j;
89
    for (i = 0; i < 4; i++) {
89
    for (i = 0; i < 4; i++) {
90
	for (j = 0; j < 4; j++)
90
	for (j = 0; j < 4; j++)
91
	    T[i][j] = 0;
91
	    T[i][j] = 0;
92
	T[i][i] = 1;
92
	T[i][i] = 1;
93
    }
93
    }
94
}
94
}
95
 
95
 
96
static void Translate (double x, double y, double z)
96
static void Translate (double x, double y, double z)
97
{
97
{
98
    Trans3d T;
98
    Trans3d T;
99
    SetToIdentity(T);
99
    SetToIdentity(T);
100
    T[3][0] = x;
100
    T[3][0] = x;
101
    T[3][1] = y;
101
    T[3][1] = y;
102
    T[3][2] = z;
102
    T[3][2] = z;
103
    Accumulate(T);
103
    Accumulate(T);
104
}
104
}
105
 
105
 
106
static void Scale (double x, double y, double z)
106
static void Scale (double x, double y, double z)
107
{
107
{
108
    Trans3d T;
108
    Trans3d T;
109
    SetToIdentity(T);
109
    SetToIdentity(T);
110
    T[0][0] = x;
110
    T[0][0] = x;
111
    T[1][1] = y;
111
    T[1][1] = y;
112
    T[2][2] = z;
112
    T[2][2] = z;
113
    Accumulate(T);
113
    Accumulate(T);
114
}
114
}
115
 
115
 
116
static void XRotate (double angle)
116
static void XRotate (double angle)
117
{
117
{
118
    double c, s;
118
    double c, s;
119
    Trans3d T;
119
    Trans3d T;
120
    SetToIdentity(T);
120
    SetToIdentity(T);
121
    c = cos(DegToRad(angle));
121
    c = cos(DegToRad(angle));
122
    s = sin(DegToRad(angle));
122
    s = sin(DegToRad(angle));
123
    T[1][1] = c;
123
    T[1][1] = c;
124
    T[2][1] = -s;
124
    T[2][1] = -s;
125
    T[2][2] = c;
125
    T[2][2] = c;
126
    T[1][2] = s;
126
    T[1][2] = s;
127
    Accumulate(T);
127
    Accumulate(T);
128
}
128
}
129
 
129
 
130
static void YRotate (double angle)
130
static void YRotate (double angle)
131
{
131
{
132
    double c, s;
132
    double c, s;
133
    Trans3d T;
133
    Trans3d T;
134
    SetToIdentity(T);
134
    SetToIdentity(T);
135
    c = cos(DegToRad(angle));
135
    c = cos(DegToRad(angle));
136
    s = sin(DegToRad(angle));
136
    s = sin(DegToRad(angle));
137
    T[0][0] = c;
137
    T[0][0] = c;
138
    T[2][0] = s;
138
    T[2][0] = s;
139
    T[2][2] = c;
139
    T[2][2] = c;
140
    T[0][2] = -s;
140
    T[0][2] = -s;
141
    Accumulate(T);
141
    Accumulate(T);
142
}
142
}
143
 
143
 
144
static void ZRotate (double angle)
144
static void ZRotate (double angle)
145
{
145
{
146
    double c, s;
146
    double c, s;
147
    Trans3d T;
147
    Trans3d T;
148
    SetToIdentity(T);
148
    SetToIdentity(T);
149
    c = cos(DegToRad(angle));
149
    c = cos(DegToRad(angle));
150
    s = sin(DegToRad(angle));
150
    s = sin(DegToRad(angle));
151
    T[0][0] = c;
151
    T[0][0] = c;
152
    T[1][0] = -s;
152
    T[1][0] = -s;
153
    T[1][1] = c;
153
    T[1][1] = c;
154
    T[0][1] = s;
154
    T[0][1] = s;
155
    Accumulate(T);
155
    Accumulate(T);
156
}
156
}
157
 
157
 
158
static void Perspective (double d)
158
static void Perspective (double d)
159
{
159
{
160
    Trans3d T;
160
    Trans3d T;
161
 
161
 
162
    SetToIdentity(T);
162
    SetToIdentity(T);
163
    T[2][3] = -1 / d;
163
    T[2][3] = -1 / d;
164
    Accumulate(T);
164
    Accumulate(T);
165
}
165
}
166
 
166
 
167
 
167
 
168
/* Stuff for labels on contour plots
168
/* Stuff for labels on contour plots
169
   Originally written by Nicholas Hildreth
169
   Originally written by Nicholas Hildreth
170
   Adapted by Paul Murrell
170
   Adapted by Paul Murrell
171
*/
171
*/
172
 
172
 
173
static
173
static
174
void FindCorners(double width, double height, SEXP label,
174
void FindCorners(double width, double height, SEXP label,
175
		 double x0, double y0, double x1, double y1,
175
		 double x0, double y0, double x1, double y1,
176
		 DevDesc *dd) {
176
		 DevDesc *dd) {
177
    double delta = height / width;
177
    double delta = height / width;
178
    double dx = GConvertXUnits(x1 - x0, USER, INCHES, dd) * delta;
178
    double dx = GConvertXUnits(x1 - x0, USER, INCHES, dd) * delta;
179
    double dy = GConvertYUnits(y1 - y0, USER, INCHES, dd) * delta;
179
    double dy = GConvertYUnits(y1 - y0, USER, INCHES, dd) * delta;
180
    dx = GConvertYUnits(dx, INCHES, USER, dd);
180
    dx = GConvertYUnits(dx, INCHES, USER, dd);
181
    dy = GConvertXUnits(dy, INCHES, USER, dd);
181
    dy = GConvertXUnits(dy, INCHES, USER, dd);
182
 
182
 
183
    REAL(label)[0] = x0 + dy;
183
    REAL(label)[0] = x0 + dy;
184
    REAL(label)[4] = y0 - dx;
184
    REAL(label)[4] = y0 - dx;
185
    REAL(label)[1] = x0 - dy;
185
    REAL(label)[1] = x0 - dy;
186
    REAL(label)[5] = y0 + dx;
186
    REAL(label)[5] = y0 + dx;
187
    REAL(label)[3] = x1 + dy;
187
    REAL(label)[3] = x1 + dy;
188
    REAL(label)[7] = y1 - dx;
188
    REAL(label)[7] = y1 - dx;
189
    REAL(label)[2] = x1 - dy;
189
    REAL(label)[2] = x1 - dy;
190
    REAL(label)[6] = y1 + dx;
190
    REAL(label)[6] = y1 + dx;
191
}
191
}
192
 
192
 
193
static
193
static
194
int TestLabelIntersection(SEXP label1, SEXP label2) {
194
int TestLabelIntersection(SEXP label1, SEXP label2) {
195
 
195
 
196
    int i, j, l1, l2;
196
    int i, j, l1, l2;
197
    double Ax, Bx, Ay, By, ax, ay, bx, by, q1, q2;
197
    double Ax, Bx, Ay, By, ax, ay, bx, by, q1, q2;
198
    double dom;
198
    double dom;
199
    double result1, result2;
199
    double result1, result2;
200
 
200
 
201
    for (i = 0; i < 4; i++) {
201
    for (i = 0; i < 4; i++) {
202
	Ax = REAL(label1)[i];
202
	Ax = REAL(label1)[i];
203
	Ay = REAL(label1)[i+4];
203
	Ay = REAL(label1)[i+4];
204
	Bx = REAL(label1)[(i+1)%4];
204
	Bx = REAL(label1)[(i+1)%4];
205
	By = REAL(label1)[(i+1)%4+4];
205
	By = REAL(label1)[(i+1)%4+4];
206
	for (j = 0; j < 4; j++) {
206
	for (j = 0; j < 4; j++) {
207
	    ax = REAL(label2)[j];
207
	    ax = REAL(label2)[j];
208
	    ay = REAL(label2)[j+4];
208
	    ay = REAL(label2)[j+4];
209
	    bx = REAL(label2)[(j+1)%4];
209
	    bx = REAL(label2)[(j+1)%4];
210
	    by = REAL(label2)[(j+1)%4+4];
210
	    by = REAL(label2)[(j+1)%4+4];
211
 
211
 
212
	    q1 = Ax*(ay-by);
212
	    q1 = Ax*(ay-by);
213
	    q2 = Ay*(bx-ax);
213
	    q2 = Ay*(bx-ax);
214
 
214
 
215
	    dom = Bx*by - Bx*ay - Ax*by + Ax*ay - bx*By + bx*Ay + ax*By - ax*Ay;
215
	    dom = Bx*by - Bx*ay - Ax*by + Ax*ay - bx*By + bx*Ay + ax*By - ax*Ay;
216
	    if (dom == 0.0) {
216
	    if (dom == 0.0) {
217
		result1 = -1;
217
		result1 = -1;
218
		result2 = -1;
218
		result2 = -1;
219
	    }
219
	    }
220
	    else {
220
	    else {
221
		result1 = (bx*Ay - ax*Ay - ay*bx - Ax*by + Ax*ay + by*ax) / dom;
221
		result1 = (bx*Ay - ax*Ay - ay*bx - Ax*by + Ax*ay + by*ax) / dom;
222
 
222
 
223
		if (bx - ax == 0.0) {
223
		if (bx - ax == 0.0) {
224
		    if (by - ay == 0.0)
224
		    if (by - ay == 0.0)
225
			result2 = -1;
225
			result2 = -1;
226
		    else
226
		    else
227
			result2 = (Ay + (By - Ay) * result1 - ay) / (by - ay);
227
			result2 = (Ay + (By - Ay) * result1 - ay) / (by - ay);
228
		}
228
		}
229
		else
229
		else
230
		    result2 = (Ax + (Bx - Ax) * result1 - ax) / (bx - ax);
230
		    result2 = (Ax + (Bx - Ax) * result1 - ax) / (bx - ax);
231
 
231
 
232
	    }
232
	    }
233
	    l1 = (result1 >= 0.0) && (result1 <= 1.0);
233
	    l1 = (result1 >= 0.0) && (result1 <= 1.0);
234
	    l2 = (result2 >= 0.0) && (result2 <= 1.0);
234
	    l2 = (result2 >= 0.0) && (result2 <= 1.0);
235
	    if (l1 && l2) return 1;
235
	    if (l1 && l2) return 1;
236
	}
236
	}
237
    }
237
    }
238
 
238
 
239
    return 0;
239
    return 0;
240
}
240
}
241
 
241
 
242
/*** Checks whether a label window is inside view region ***/
242
/*** Checks whether a label window is inside view region ***/
243
static int LabelInsideWindow(SEXP label, DevDesc *dd) {
243
static int LabelInsideWindow(SEXP label, DevDesc *dd) {
244
    int i = 0;
244
    int i = 0;
245
    double x, y;
245
    double x, y;
246
 
246
 
247
    while (i < 4) {
247
    while (i < 4) {
248
	x = REAL(label)[i];
248
	x = REAL(label)[i];
249
	y = REAL(label)[i+4];
249
	y = REAL(label)[i+4];
250
	GConvert(&x, &y, USER, NDC, dd);
250
	GConvert(&x, &y, USER, NDC, dd);
251
	/*	x = GConvertXUnits(REAL(label)[i], USER, NDC, dd);
251
	/*	x = GConvertXUnits(REAL(label)[i], USER, NDC, dd);
252
		y = GConvertYUnits(REAL(label)[i+4], USER, NDC, dd); */
252
		y = GConvertYUnits(REAL(label)[i+4], USER, NDC, dd); */
253
 
253
 
254
	if ((x < 0) || (x > 1) ||
254
	if ((x < 0) || (x > 1) ||
255
	    (y < 0) || (y > 1))
255
	    (y < 0) || (y > 1))
256
	    return 1;
256
	    return 1;
257
	i += 1;
257
	i += 1;
258
    }
258
    }
259
    return 0;
259
    return 0;
260
}
260
}
261
 
261
 
262
 
262
 
263
	/*  C o n t o u r   P l o t t i n g  */
263
	/*  C o n t o u r   P l o t t i n g  */
264
 
264
 
265
typedef struct SEG {
265
typedef struct SEG {
266
    struct SEG *next;
266
    struct SEG *next;
267
    double x0;
267
    double x0;
268
    double y0;
268
    double y0;
269
    double x1;
269
    double x1;
270
    double y1;
270
    double y1;
271
} SEG, *SEGP;
271
} SEG, *SEGP;
272
 
272
 
273
static SEGP *ctr_SegDB;
273
static SEGP *ctr_SegDB;
274
 
274
 
275
static int ctr_intersect(double z0, double z1, double zc, double *f)
275
static int ctr_intersect(double z0, double z1, double zc, double *f)
276
{
276
{
277
    if ((z0 - zc) * (z1 - zc) < 0.0) {
277
    if ((z0 - zc) * (z1 - zc) < 0.0) {
278
	*f = (zc - z0) / (z1 -	z0);
278
	*f = (zc - z0) / (z1 -	z0);
279
	return 1;
279
	return 1;
280
    }
280
    }
281
    return 0;
281
    return 0;
282
}
282
}
283
 
283
 
284
static SEGP ctr_newseg(double x0, double y0, double x1, double y1, SEGP prev)
284
static SEGP ctr_newseg(double x0, double y0, double x1, double y1, SEGP prev)
285
{
285
{
286
    SEGP seg = (SEGP)R_alloc(1, sizeof(SEG));
286
    SEGP seg = (SEGP)R_alloc(1, sizeof(SEG));
287
    seg->x0 = x0;
287
    seg->x0 = x0;
288
    seg->y0 = y0;
288
    seg->y0 = y0;
289
    seg->x1 = x1;
289
    seg->x1 = x1;
290
    seg->y1 = y1;
290
    seg->y1 = y1;
291
    seg->next = prev;
291
    seg->next = prev;
292
    return seg;
292
    return seg;
293
}
293
}
294
 
294
 
295
static void ctr_swapseg(SEGP seg)
295
static void ctr_swapseg(SEGP seg)
296
{
296
{
297
    double x, y;
297
    double x, y;
298
    x = seg->x0;
298
    x = seg->x0;
299
    y = seg->y0;
299
    y = seg->y0;
300
    seg->x0 = seg->x1;
300
    seg->x0 = seg->x1;
301
    seg->y0 = seg->y1;
301
    seg->y0 = seg->y1;
302
    seg->x1 = x;
302
    seg->x1 = x;
303
    seg->y1 = y;
303
    seg->y1 = y;
304
}
304
}
305
 
305
 
306
	/* ctr_segdir(): Determine the entry direction to the next cell */
306
	/* ctr_segdir(): Determine the entry direction to the next cell */
307
	/* and update the cell indices */
307
	/* and update the cell indices */
308
 
308
 
309
#define XMATCH(x0,x1) (fabs(x0-x1) == 0)
309
#define XMATCH(x0,x1) (fabs(x0-x1) == 0)
310
#define YMATCH(y0,y1) (fabs(y0-y1) == 0)
310
#define YMATCH(y0,y1) (fabs(y0-y1) == 0)
311
 
311
 
312
static int ctr_segdir(double xend, double yend, double *x, double *y,
312
static int ctr_segdir(double xend, double yend, double *x, double *y,
313
		      int *i, int *j, int nx, int ny)
313
		      int *i, int *j, int nx, int ny)
314
{
314
{
315
    if (YMATCH(yend, y[*j])) {
315
    if (YMATCH(yend, y[*j])) {
316
	if (*j == 0)
316
	if (*j == 0)
317
	    return 0;
317
	    return 0;
318
	*j = *j - 1;
318
	*j = *j - 1;
319
	return 3;
319
	return 3;
320
    }
320
    }
321
    if (XMATCH(xend, x[*i])) {
321
    if (XMATCH(xend, x[*i])) {
322
	if (*i == 0)
322
	if (*i == 0)
323
	    return 0;
323
	    return 0;
324
	*i = *i - 1;
324
	*i = *i - 1;
325
	return 4;
325
	return 4;
326
    }
326
    }
327
    if (YMATCH(yend, y[*j + 1])) {
327
    if (YMATCH(yend, y[*j + 1])) {
328
	if (*j >= ny - 1)
328
	if (*j >= ny - 1)
329
	    return 0;
329
	    return 0;
330
	*j = *j + 1;
330
	*j = *j + 1;
331
	return 1;
331
	return 1;
332
    }
332
    }
333
    if (XMATCH(xend, x[*i + 1])) {
333
    if (XMATCH(xend, x[*i + 1])) {
334
	if (*i >= nx - 1)
334
	if (*i >= nx - 1)
335
	    return 0;
335
	    return 0;
336
	*i = *i + 1;
336
	*i = *i + 1;
337
	return 2;
337
	return 2;
338
    }
338
    }
339
    return 0;
339
    return 0;
340
}
340
}
341
 
341
 
342
/* Search seglist for a segment with endpoint (xend, yend). */
342
/* Search seglist for a segment with endpoint (xend, yend). */
343
/* The cell entry direction is dir, and if tail=1/0 we are */
343
/* The cell entry direction is dir, and if tail=1/0 we are */
344
/* building the tail/head of a contour.	 The matching segment */
344
/* building the tail/head of a contour.	 The matching segment */
345
/* is pointed to by seg and the updated segment list (with */
345
/* is pointed to by seg and the updated segment list (with */
346
/* the matched segment stripped) is returned by the funtion. */
346
/* the matched segment stripped) is returned by the funtion. */
347
 
347
 
348
static SEGP ctr_segupdate(double xend, double yend, int dir, Rboolean tail,
348
static SEGP ctr_segupdate(double xend, double yend, int dir, Rboolean tail,
349
			  SEGP seglist, SEGP* seg)
349
			  SEGP seglist, SEGP* seg)
350
{
350
{
351
    if (seglist == NULL) {
351
    if (seglist == NULL) {
352
	*seg = NULL;
352
	*seg = NULL;
353
	return NULL;
353
	return NULL;
354
    }
354
    }
355
    switch (dir) {
355
    switch (dir) {
356
    case 1:
356
    case 1:
357
    case 3:
357
    case 3:
358
	if (YMATCH(yend,seglist->y0)) {
358
	if (YMATCH(yend,seglist->y0)) {
359
	    if (!tail)
359
	    if (!tail)
360
		ctr_swapseg(seglist);
360
		ctr_swapseg(seglist);
361
	    *seg = seglist;
361
	    *seg = seglist;
362
	    return seglist->next;
362
	    return seglist->next;
363
	}
363
	}
364
	if (YMATCH(yend,seglist->y1)) {
364
	if (YMATCH(yend,seglist->y1)) {
365
	    if (tail)
365
	    if (tail)
366
		ctr_swapseg(seglist);
366
		ctr_swapseg(seglist);
367
	    *seg = seglist;
367
	    *seg = seglist;
368
	    return seglist->next;
368
	    return seglist->next;
369
	}
369
	}
370
	break;
370
	break;
371
    case 2:
371
    case 2:
372
    case 4:
372
    case 4:
373
	if (XMATCH(xend,seglist->x0)) {
373
	if (XMATCH(xend,seglist->x0)) {
374
	    if (!tail)
374
	    if (!tail)
375
		ctr_swapseg(seglist);
375
		ctr_swapseg(seglist);
376
	    *seg = seglist;
376
	    *seg = seglist;
377
	    return seglist->next;
377
	    return seglist->next;
378
	}
378
	}
379
	if (XMATCH(xend,seglist->x1)) {
379
	if (XMATCH(xend,seglist->x1)) {
380
	    if (tail)
380
	    if (tail)
381
		ctr_swapseg(seglist);
381
		ctr_swapseg(seglist);
382
	    *seg = seglist;
382
	    *seg = seglist;
383
	    return seglist->next;
383
	    return seglist->next;
384
	}
384
	}
385
	break;
385
	break;
386
    }
386
    }
387
    seglist->next = ctr_segupdate(xend, yend, dir, tail, seglist->next, seg);
387
    seglist->next = ctr_segupdate(xend, yend, dir, tail, seglist->next, seg);
388
    return seglist;
388
    return seglist;
389
}
389
}
390
 
390
 
391
/* labelList, label1, and label2 are all SEXPs rather than being allocated
391
/* labelList, label1, and label2 are all SEXPs rather than being allocated
392
   using R_alloc because they need to persist across calls to contour().
392
   using R_alloc because they need to persist across calls to contour().
393
   In do_contour() there is a vmaxget() ... vmaxset() around each call to
393
   In do_contour() there is a vmaxget() ... vmaxset() around each call to
394
   contour() to release all of the memory used in the drawing of the
394
   contour() to release all of the memory used in the drawing of the
395
   contour _lines_ at each contour level.  We need to keep track of the
395
   contour _lines_ at each contour level.  We need to keep track of the
396
   contour _labels_ for _all_ contour levels, hence we have to use a
396
   contour _labels_ for _all_ contour levels, hence we have to use a
397
   different memory allocation mechanism.
397
   different memory allocation mechanism.
398
*/
398
*/
399
static SEXP labelList;
399
static SEXP labelList;
400
 
400
 
401
static
401
static
402
double distFromEdge(double *xxx, double *yyy, int iii, DevDesc *dd) {
402
double distFromEdge(double *xxx, double *yyy, int iii, DevDesc *dd) {
403
    return fmin2(fmin2(xxx[iii]-Rf_gpptr(dd)->usr[0], Rf_gpptr(dd)->usr[1]-xxx[iii]),
403
    return fmin2(fmin2(xxx[iii]-Rf_gpptr(dd)->usr[0], Rf_gpptr(dd)->usr[1]-xxx[iii]),
404
		 fmin2(yyy[iii]-Rf_gpptr(dd)->usr[2], Rf_gpptr(dd)->usr[3]-yyy[iii]));
404
		 fmin2(yyy[iii]-Rf_gpptr(dd)->usr[2], Rf_gpptr(dd)->usr[3]-yyy[iii]));
405
}
405
}
406
 
406
 
407
static
407
static
408
Rboolean useStart(double *xxx, double *yyy, int ns, DevDesc *dd) {
408
Rboolean useStart(double *xxx, double *yyy, int ns, DevDesc *dd) {
409
    if (distFromEdge(xxx, yyy, 0, dd) < distFromEdge(xxx, yyy, ns-1, dd))
409
    if (distFromEdge(xxx, yyy, 0, dd) < distFromEdge(xxx, yyy, ns-1, dd))
410
	return TRUE;
410
	return TRUE;
411
    else
411
    else
412
	return FALSE;
412
	return FALSE;
413
}
413
}
414
 
414
 
415
static
415
static
416
int findGapUp(double *xxx, double *yyy, int ns, double labelDistance,
416
int findGapUp(double *xxx, double *yyy, int ns, double labelDistance,
417
	      DevDesc *dd) {
417
	      DevDesc *dd) {
418
    double dX, dY;
418
    double dX, dY;
419
    double dXC, dYC;
419
    double dXC, dYC;
420
    double distanceSum = 0;
420
    double distanceSum = 0;
421
    int n = 0;
421
    int n = 0;
422
    int jjj = 1;
422
    int jjj = 1;
423
    while ((jjj < ns) && (distanceSum < labelDistance)) {
423
    while ((jjj < ns) && (distanceSum < labelDistance)) {
424
	/* Find a gap big enough for the label
424
	/* Find a gap big enough for the label
425
	   use several segments if necessary
425
	   use several segments if necessary
426
	*/
426
	*/
427
	dX = xxx[jjj] - xxx[jjj - n - 1]; /* jjj - n - 1 == 0 */
427
	dX = xxx[jjj] - xxx[jjj - n - 1]; /* jjj - n - 1 == 0 */
428
	dY = yyy[jjj] - yyy[jjj - n - 1];
428
	dY = yyy[jjj] - yyy[jjj - n - 1];
429
	dXC = GConvertXUnits(dX, USER, INCHES, dd);
429
	dXC = GConvertXUnits(dX, USER, INCHES, dd);
430
	dYC = GConvertYUnits(dY, USER, INCHES, dd);
430
	dYC = GConvertYUnits(dY, USER, INCHES, dd);
431
	distanceSum = hypot(dXC, dYC);
431
	distanceSum = hypot(dXC, dYC);
432
	jjj++;
432
	jjj++;
433
	n++;
433
	n++;
434
    }
434
    }
435
    if (distanceSum < labelDistance)
435
    if (distanceSum < labelDistance)
436
	return 0;
436
	return 0;
437
    else
437
    else
438
	return n;
438
	return n;
439
}
439
}
440
 
440
 
441
static
441
static
442
int findGapDown(double *xxx, double *yyy, int ns, double labelDistance,
442
int findGapDown(double *xxx, double *yyy, int ns, double labelDistance,
443
		DevDesc *dd) {
443
		DevDesc *dd) {
444
    double dX, dY;
444
    double dX, dY;
445
    double dXC, dYC;
445
    double dXC, dYC;
446
    double distanceSum = 0;
446
    double distanceSum = 0;
447
    int n = 0;
447
    int n = 0;
448
    int jjj = ns - 2;
448
    int jjj = ns - 2;
449
    while ((jjj > -1) && (distanceSum < labelDistance)) {
449
    while ((jjj > -1) && (distanceSum < labelDistance)) {
450
	/* Find a gap big enough for the label
450
	/* Find a gap big enough for the label
451
	   use several segments if necessary
451
	   use several segments if necessary
452
	*/
452
	*/
453
	dX = xxx[jjj] - xxx[jjj + n + 1]; /*jjj + n + 1 == ns -1 */
453
	dX = xxx[jjj] - xxx[jjj + n + 1]; /*jjj + n + 1 == ns -1 */
454
	dY = yyy[jjj] - yyy[jjj + n + 1];
454
	dY = yyy[jjj] - yyy[jjj + n + 1];
455
	dXC = GConvertXUnits(dX, USER, INCHES, dd);
455
	dXC = GConvertXUnits(dX, USER, INCHES, dd);
456
	dYC = GConvertYUnits(dY, USER, INCHES, dd);
456
	dYC = GConvertYUnits(dY, USER, INCHES, dd);
457
	distanceSum = hypot(dXC, dYC);
457
	distanceSum = hypot(dXC, dYC);
458
	jjj--;
458
	jjj--;
459
	n++;
459
	n++;
460
    }
460
    }
461
    if (distanceSum < labelDistance)
461
    if (distanceSum < labelDistance)
462
	return 0;
462
	return 0;
463
    else
463
    else
464
	return n;
464
	return n;
465
}
465
}
466
 
466
 
467
/*
467
/*
468
 * Generate a list of segments for a single level
468
 * Generate a list of segments for a single level
469
 */
469
 */
470
static SEGP* contourLines(double *x, int nx, double *y, int ny,
470
static SEGP* contourLines(double *x, int nx, double *y, int ny,
471
			 double *z, double zc, double atom)
471
			 double *z, double zc, double atom)
472
{
472
{
473
    double f, xl, xh, yl, yh, zll, zhl, zlh, zhh, xx[4], yy[4];
473
    double f, xl, xh, yl, yh, zll, zhl, zlh, zhh, xx[4], yy[4];
474
    int i, j, k, l, m, nacode;
474
    int i, j, k, l, m, nacode;
475
    SEGP seglist;
475
    SEGP seglist;
476
    SEGP *segmentDB;
476
    SEGP *segmentDB;
477
    /* Initialize the segment data base */
477
    /* Initialize the segment data base */
478
    /* Note we must be careful about resetting */
478
    /* Note we must be careful about resetting */
479
    /* the top of the stack, otherwise we run out of */
479
    /* the top of the stack, otherwise we run out of */
480
    /* memory after a sequence of displaylist replays */
480
    /* memory after a sequence of displaylist replays */
481
    /*
481
    /*
482
     * This reset is done out in GEcontourLines
482
     * This reset is done out in GEcontourLines
483
     */
483
     */
484
    segmentDB = (SEGP*)R_alloc(nx*ny, sizeof(SEGP));
484
    segmentDB = (SEGP*)R_alloc(nx*ny, sizeof(SEGP));
485
    for (i = 0; i < nx; i++)
485
    for (i = 0; i < nx; i++)
486
	for (j = 0; j < ny; j++)
486
	for (j = 0; j < ny; j++)
487
	    segmentDB[i + j * nx] = NULL;
487
	    segmentDB[i + j * nx] = NULL;
488
    for (i = 0; i < nx - 1; i++) {
488
    for (i = 0; i < nx - 1; i++) {
489
	xl = x[i];
489
	xl = x[i];
490
	xh = x[i + 1];
490
	xh = x[i + 1];
491
	for (j = 0; j < ny - 1; j++) {
491
	for (j = 0; j < ny - 1; j++) {
492
	    yl = y[j];
492
	    yl = y[j];
493
	    yh = y[j + 1];
493
	    yh = y[j + 1];
494
	    k = i + j * nx;
494
	    k = i + j * nx;
495
	    zll = z[k];
495
	    zll = z[k];
496
	    zhl = z[k + 1];
496
	    zhl = z[k + 1];
497
	    zlh = z[k + nx];
497
	    zlh = z[k + nx];
498
	    zhh = z[k + nx + 1];
498
	    zhh = z[k + nx + 1];
499
 
499
 
500
	    /* If the value at a corner is exactly equal to a contour level,
500
	    /* If the value at a corner is exactly equal to a contour level,
501
	     * change that value by a tiny amount */
501
	     * change that value by a tiny amount */
502
 
502
 
503
	    if (zll == zc) zll += atom;
503
	    if (zll == zc) zll += atom;
504
	    if (zhl == zc) zhl += atom;
504
	    if (zhl == zc) zhl += atom;
505
	    if (zlh == zc) zlh += atom;
505
	    if (zlh == zc) zlh += atom;
506
	    if (zhh == zc) zhh += atom;
506
	    if (zhh == zc) zhh += atom;
507
#ifdef DEBUG_contour
507
#ifdef DEBUG_contour
508
	    /* Haven't seen this happening (MM): */
508
	    /* Haven't seen this happening (MM): */
509
	    if (zll == zc) REprintf(" [%d,%d] ll: %g\n",i,j, zll);
509
	    if (zll == zc) REprintf(" [%d,%d] ll: %g\n",i,j, zll);
510
	    if (zhl == zc) REprintf(" [%d,%d] hl: %g\n",i,j, zhl);
510
	    if (zhl == zc) REprintf(" [%d,%d] hl: %g\n",i,j, zhl);
511
	    if (zlh == zc) REprintf(" [%d,%d] lh: %g\n",i,j, zlh);
511
	    if (zlh == zc) REprintf(" [%d,%d] lh: %g\n",i,j, zlh);
512
	    if (zhh == zc) REprintf(" [%d,%d] hh: %g\n",i,j, zhh);
512
	    if (zhh == zc) REprintf(" [%d,%d] hh: %g\n",i,j, zhh);
513
#endif
513
#endif
514
	    /* Check for intersections with sides */
514
	    /* Check for intersections with sides */
515
 
515
 
516
	    nacode = 0;
516
	    nacode = 0;
517
	    if (R_FINITE(zll)) nacode += 1;
517
	    if (R_FINITE(zll)) nacode += 1;
518
	    if (R_FINITE(zhl)) nacode += 2;
518
	    if (R_FINITE(zhl)) nacode += 2;
519
	    if (R_FINITE(zlh)) nacode += 4;
519
	    if (R_FINITE(zlh)) nacode += 4;
520
	    if (R_FINITE(zhh)) nacode += 8;
520
	    if (R_FINITE(zhh)) nacode += 8;
521
 
521
 
522
	    k = 0;
522
	    k = 0;
523
	    switch (nacode) {
523
	    switch (nacode) {
524
	    case 15:
524
	    case 15:
525
		if (ctr_intersect(zll, zhl, zc, &f)) {
525
		if (ctr_intersect(zll, zhl, zc, &f)) {
526
		    xx[k] = xl + f * (xh - xl);
526
		    xx[k] = xl + f * (xh - xl);
527
		    yy[k] = yl; k++;
527
		    yy[k] = yl; k++;
528
		}
528
		}
529
		if (ctr_intersect(zll, zlh, zc, &f)) {
529
		if (ctr_intersect(zll, zlh, zc, &f)) {
530
		    yy[k] = yl + f * (yh - yl);
530
		    yy[k] = yl + f * (yh - yl);
531
		    xx[k] = xl; k++;
531
		    xx[k] = xl; k++;
532
		}
532
		}
533
		if (ctr_intersect(zhl, zhh, zc, &f)) {
533
		if (ctr_intersect(zhl, zhh, zc, &f)) {
534
		    yy[k] = yl + f * (yh - yl);
534
		    yy[k] = yl + f * (yh - yl);
535
		    xx[k] = xh; k++;
535
		    xx[k] = xh; k++;
536
		}
536
		}
537
		if (ctr_intersect(zlh, zhh, zc, &f)) {
537
		if (ctr_intersect(zlh, zhh, zc, &f)) {
538
		    xx[k] = xl + f * (xh - xl);
538
		    xx[k] = xl + f * (xh - xl);
539
		    yy[k] = yh; k++;
539
		    yy[k] = yh; k++;
540
		}
540
		}
541
		break;
541
		break;
542
	    case 14:
542
	    case 14:
543
		if (ctr_intersect(zhl, zhh, zc, &f)) {
543
		if (ctr_intersect(zhl, zhh, zc, &f)) {
544
		    yy[k] = yl + f * (yh - yl);
544
		    yy[k] = yl + f * (yh - yl);
545
		    xx[k] = xh; k++;
545
		    xx[k] = xh; k++;
546
		}
546
		}
547
		if (ctr_intersect(zlh, zhh, zc, &f)) {
547
		if (ctr_intersect(zlh, zhh, zc, &f)) {
548
		    xx[k] = xl + f * (xh - xl);
548
		    xx[k] = xl + f * (xh - xl);
549
		    yy[k] = yh; k++;
549
		    yy[k] = yh; k++;
550
		}
550
		}
551
		if (ctr_intersect(zlh, zhl, zc, &f)) {
551
		if (ctr_intersect(zlh, zhl, zc, &f)) {
552
		    xx[k] = xl + f * (xh - xl);
552
		    xx[k] = xl + f * (xh - xl);
553
		    yy[k] = yh + f * (yl - yh);
553
		    yy[k] = yh + f * (yl - yh);
554
		    k++;
554
		    k++;
555
		}
555
		}
556
		break;
556
		break;
557
	    case 13:
557
	    case 13:
558
		if (ctr_intersect(zll, zlh, zc, &f)) {
558
		if (ctr_intersect(zll, zlh, zc, &f)) {
559
		    yy[k] = yl + f * (yh - yl);
559
		    yy[k] = yl + f * (yh - yl);
560
		    xx[k] = xl; k++;
560
		    xx[k] = xl; k++;
561
		}
561
		}
562
		if (ctr_intersect(zlh, zhh, zc, &f)) {
562
		if (ctr_intersect(zlh, zhh, zc, &f)) {
563
		    xx[k] = xl + f * (xh - xl);
563
		    xx[k] = xl + f * (xh - xl);
564
		    yy[k] = yh; k++;
564
		    yy[k] = yh; k++;
565
		}
565
		}
566
		if (ctr_intersect(zll, zhh, zc, &f)) {
566
		if (ctr_intersect(zll, zhh, zc, &f)) {
567
		    xx[k] = xl + f * (xh - xl);
567
		    xx[k] = xl + f * (xh - xl);
568
		    yy[k] = yl + f * (yh - yl);
568
		    yy[k] = yl + f * (yh - yl);
569
		    k++;
569
		    k++;
570
		}
570
		}
571
		break;
571
		break;
572
	    case 11:
572
	    case 11:
573
		if (ctr_intersect(zhl, zhh, zc, &f)) {
573
		if (ctr_intersect(zhl, zhh, zc, &f)) {
574
		    yy[k] = yl + f * (yh - yl);
574
		    yy[k] = yl + f * (yh - yl);
575
		    xx[k] = xh; k++;
575
		    xx[k] = xh; k++;
576
		}
576
		}
577
		if (ctr_intersect(zll, zhl, zc, &f)) {
577
		if (ctr_intersect(zll, zhl, zc, &f)) {
578
		    xx[k] = xl + f * (xh - xl);
578
		    xx[k] = xl + f * (xh - xl);
579
		    yy[k] = yl; k++;
579
		    yy[k] = yl; k++;
580
		}
580
		}
581
		if (ctr_intersect(zll, zhh, zc, &f)) {
581
		if (ctr_intersect(zll, zhh, zc, &f)) {
582
		    xx[k] = xl + f * (xh - xl);
582
		    xx[k] = xl + f * (xh - xl);
583
		    yy[k] = yl + f * (yh - yl);
583
		    yy[k] = yl + f * (yh - yl);
584
		    k++;
584
		    k++;
585
		}
585
		}
586
		break;
586
		break;
587
	    case 7:
587
	    case 7:
588
		if (ctr_intersect(zll, zlh, zc, &f)) {
588
		if (ctr_intersect(zll, zlh, zc, &f)) {
589
		    yy[k] = yl + f * (yh - yl);
589
		    yy[k] = yl + f * (yh - yl);
590
		    xx[k] = xl; k++;
590
		    xx[k] = xl; k++;
591
		}
591
		}
592
		if (ctr_intersect(zll, zhl, zc, &f)) {
592
		if (ctr_intersect(zll, zhl, zc, &f)) {
593
		    xx[k] = xl + f * (xh - xl);
593
		    xx[k] = xl + f * (xh - xl);
594
		    yy[k] = yl; k++;
594
		    yy[k] = yl; k++;
595
		}
595
		}
596
		if (ctr_intersect(zlh, zhl, zc, &f)) {
596
		if (ctr_intersect(zlh, zhl, zc, &f)) {
597
		    xx[k] = xl + f * (xh - xl);
597
		    xx[k] = xl + f * (xh - xl);
598
		    yy[k] = yh + f * (yl - yh);
598
		    yy[k] = yh + f * (yl - yh);
599
		    k++;
599
		    k++;
600
		}
600
		}
601
		break;
601
		break;
602
	    }
602
	    }
603
 
603
 
604
	    /* We now have k(=2,4) endpoints */
604
	    /* We now have k(=2,4) endpoints */
605
	    /* Decide which to join */
605
	    /* Decide which to join */
606
 
606
 
607
	    seglist = NULL;
607
	    seglist = NULL;
608
 
608
 
609
	    if (k > 0) {
609
	    if (k > 0) {
610
		if (k == 2) {
610
		if (k == 2) {
611
		    seglist = ctr_newseg(xx[0], yy[0], xx[1], yy[1], seglist);
611
		    seglist = ctr_newseg(xx[0], yy[0], xx[1], yy[1], seglist);
612
		}
612
		}
613
		else if (k == 4) {
613
		else if (k == 4) {
614
		    for (k = 3; k >= 1; k--) {
614
		    for (k = 3; k >= 1; k--) {
615
			m = k;
615
			m = k;
616
			xl = xx[k];
616
			xl = xx[k];
617
			for (l = 0; l < k; l++) {
617
			for (l = 0; l < k; l++) {
618
			    if (xx[l] > xl) {
618
			    if (xx[l] > xl) {
619
				xl = xx[l];
619
				xl = xx[l];
620
				m = l;
620
				m = l;
621
			    }
621
			    }
622
			}
622
			}
623
			if (m != k) {
623
			if (m != k) {
624
			    xl = xx[k];
624
			    xl = xx[k];
625
			    yl = yy[k];
625
			    yl = yy[k];
626
			    xx[k] = xx[m];
626
			    xx[k] = xx[m];
627
			    yy[k] = yy[m];
627
			    yy[k] = yy[m];
628
			    xx[m] = xl;
628
			    xx[m] = xl;
629
			    yy[m] = yl;
629
			    yy[m] = yl;
630
			}
630
			}
631
		    }
631
		    }
632
		    seglist = ctr_newseg(xx[0], yy[0], xx[1], yy[1], seglist);
632
		    seglist = ctr_newseg(xx[0], yy[0], xx[1], yy[1], seglist);
633
		    seglist = ctr_newseg(xx[2], yy[2], xx[3], yy[3], seglist);
633
		    seglist = ctr_newseg(xx[2], yy[2], xx[3], yy[3], seglist);
634
		}
634
		}
635
		else error("k != 2 or 4");
635
		else error("k != 2 or 4");
636
	    }
636
	    }
637
	    segmentDB[i + j * nx] = seglist;
637
	    segmentDB[i + j * nx] = seglist;
638
	}
638
	}
639
    }
639
    }
640
    return segmentDB;
640
    return segmentDB;
641
}
641
}
642
 
642
 
643
#define CONTOUR_LIST_STEP 100
643
#define CONTOUR_LIST_STEP 100
644
#define CONTOUR_LIST_LEVEL 0
644
#define CONTOUR_LIST_LEVEL 0
645
#define CONTOUR_LIST_X 1
645
#define CONTOUR_LIST_X 1
646
#define CONTOUR_LIST_Y 2
646
#define CONTOUR_LIST_Y 2
647
 
647
 
648
static SEXP growList(SEXP oldlist) {
648
static SEXP growList(SEXP oldlist) {
649
    int i, len;
649
    int i, len;
650
    SEXP templist;
650
    SEXP templist;
651
    len = LENGTH(oldlist);
651
    len = LENGTH(oldlist);
652
    templist = PROTECT(allocVector(VECSXP, len + CONTOUR_LIST_STEP));
652
    templist = PROTECT(allocVector(VECSXP, len + CONTOUR_LIST_STEP));
653
    for (i=0; i<len; i++)
653
    for (i=0; i<len; i++)
654
	SET_VECTOR_ELT(templist, i, VECTOR_ELT(oldlist, i));
654
	SET_VECTOR_ELT(templist, i, VECTOR_ELT(oldlist, i));
655
    UNPROTECT(1);
655
    UNPROTECT(1);
656
    return templist;
656
    return templist;
657
}
657
}
658
 
658
 
659
/*
659
/*
660
 * Store the list of segments for a single level in the SEXP
660
 * Store the list of segments for a single level in the SEXP
661
 * list that will be returned to the user
661
 * list that will be returned to the user
662
 */
662
 */
663
static
663
static
664
int addContourLines(double *x, int nx, double *y, int ny,
664
int addContourLines(double *x, int nx, double *y, int ny,
665
		     double *z, double zc, double atom,
665
		     double *z, double zc, double atom,
666
		     SEGP* segmentDB, int nlines, SEXP container)
666
		     SEGP* segmentDB, int nlines, SEXP container)
667
{
667
{
668
    double xend, yend;
668
    double xend, yend;
669
    int i, ii, j, jj, ns, ns2, dir, nc;
669
    int i, ii, j, jj, ns, ns2, dir, nc;
670
    SEGP seglist, seg, s, start, end;
670
    SEGP seglist, seg, s, start, end;
671
    SEXP ctr, level, xsxp, ysxp, names;
671
    SEXP ctr, level, xsxp, ysxp, names;
672
    /* Begin following contours. */
672
    /* Begin following contours. */
673
    /* 1. Grab a segment */
673
    /* 1. Grab a segment */
674
    /* 2. Follow its tail */
674
    /* 2. Follow its tail */
675
    /* 3. Follow its head */
675
    /* 3. Follow its head */
676
    /* 4. Save the contour */
676
    /* 4. Save the contour */
677
    for (i = 0; i < nx - 1; i++)
677
    for (i = 0; i < nx - 1; i++)
678
	for (j = 0; j < ny - 1; j++) {
678
	for (j = 0; j < ny - 1; j++) {
679
	    while ((seglist = segmentDB[i + j * nx])) {
679
	    while ((seglist = segmentDB[i + j * nx])) {
680
		ii = i; jj = j;
680
		ii = i; jj = j;
681
		start = end = seglist;
681
		start = end = seglist;
682
		segmentDB[i + j * nx] = seglist->next;
682
		segmentDB[i + j * nx] = seglist->next;
683
		xend = seglist->x1;
683
		xend = seglist->x1;
684
		yend = seglist->y1;
684
		yend = seglist->y1;
685
		while ((dir = ctr_segdir(xend, yend, x, y,
685
		while ((dir = ctr_segdir(xend, yend, x, y,
686
					 &ii, &jj, nx, ny))) {
686
					 &ii, &jj, nx, ny))) {
687
		    segmentDB[ii + jj * nx]
687
		    segmentDB[ii + jj * nx]
688
			= ctr_segupdate(xend, yend, dir, TRUE,/* = tail */
688
			= ctr_segupdate(xend, yend, dir, TRUE,/* = tail */
689
					segmentDB[ii + jj * nx], &seg);
689
					segmentDB[ii + jj * nx], &seg);
690
		    if (!seg) break;
690
		    if (!seg) break;
691
		    end->next = seg;
691
		    end->next = seg;
692
		    end = seg;
692
		    end = seg;
693
		    xend = end->x1;
693
		    xend = end->x1;
694
		    yend = end->y1;
694
		    yend = end->y1;
695
		}
695
		}
696
		end->next = NULL; /* <<< new for 1.2.3 */
696
		end->next = NULL; /* <<< new for 1.2.3 */
697
		ii = i; jj = j;
697
		ii = i; jj = j;
698
		xend = seglist->x0;
698
		xend = seglist->x0;
699
		yend = seglist->y0;
699
		yend = seglist->y0;
700
		while ((dir = ctr_segdir(xend, yend, x, y,
700
		while ((dir = ctr_segdir(xend, yend, x, y,
701
					 &ii, &jj, nx, ny))) {
701
					 &ii, &jj, nx, ny))) {
702
		    segmentDB[ii + jj * nx]
702
		    segmentDB[ii + jj * nx]
703
			= ctr_segupdate(xend, yend, dir, FALSE,/* ie. head */
703
			= ctr_segupdate(xend, yend, dir, FALSE,/* ie. head */
704
					segmentDB[ii+jj*nx], &seg);
704
					segmentDB[ii+jj*nx], &seg);
705
		    if (!seg) break;
705
		    if (!seg) break;
706
		    seg->next = start;
706
		    seg->next = start;
707
		    start = seg;
707
		    start = seg;
708
		    xend = start->x0;
708
		    xend = start->x0;
709
		    yend = start->y0;
709
		    yend = start->y0;
710
		}
710
		}
711
 
711
 
712
		/* ns := #{segments of polyline} -- need to allocate */
712
		/* ns := #{segments of polyline} -- need to allocate */
713
		s = start;
713
		s = start;
714
		ns = 0;
714
		ns = 0;
715
		/* max_contour_segments: prevent inf.loop (shouldn't be needed) */
715
		/* max_contour_segments: prevent inf.loop (shouldn't be needed) */
716
		while (s && ns < max_contour_segments) {
716
		while (s && ns < max_contour_segments) {
717
		    ns++;
717
		    ns++;
718
		    s = s->next;
718
		    s = s->next;
719
		}
719
		}
720
		if(ns == max_contour_segments)
720
		if(ns == max_contour_segments)
721
		    warning(_("contour(): circular/long seglist -- bug.report()!"));
721
		    warning(_("contour(): circular/long seglist -- bug.report()!"));
722
 
722
 
723
		/* countour midpoint : use for labelling sometime (not yet!) */
723
		/* countour midpoint : use for labelling sometime (not yet!) */
724
		if (ns > 3) ns2 = ns/2; else ns2 = -1;
724
		if (ns > 3) ns2 = ns/2; else ns2 = -1;
725
 
725
 
726
		/*
726
		/*
727
		 * "write" the contour locations into the list of contours
727
		 * "write" the contour locations into the list of contours
728
		 */
728
		 */
729
		ctr = PROTECT(allocVector(VECSXP, 3));
729
		ctr = PROTECT(allocVector(VECSXP, 3));
730
		level = PROTECT(allocVector(REALSXP, 1));
730
		level = PROTECT(allocVector(REALSXP, 1));
731
		xsxp = PROTECT(allocVector(REALSXP, ns + 1));
731
		xsxp = PROTECT(allocVector(REALSXP, ns + 1));
732
		ysxp = PROTECT(allocVector(REALSXP, ns + 1));
732
		ysxp = PROTECT(allocVector(REALSXP, ns + 1));
733
		REAL(level)[0] = zc;
733
		REAL(level)[0] = zc;
734
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_LEVEL, level);
734
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_LEVEL, level);
735
		s = start;
735
		s = start;
736
		REAL(xsxp)[0] = s->x0;
736
		REAL(xsxp)[0] = s->x0;
737
		REAL(ysxp)[0] = s->y0;
737
		REAL(ysxp)[0] = s->y0;
738
		ns = 1;
738
		ns = 1;
739
		while (s->next && ns < max_contour_segments) {
739
		while (s->next && ns < max_contour_segments) {
740
		    s = s->next;
740
		    s = s->next;
741
		    REAL(xsxp)[ns] = s->x0;
741
		    REAL(xsxp)[ns] = s->x0;
742
		    REAL(ysxp)[ns++] = s->y0;
742
		    REAL(ysxp)[ns++] = s->y0;
743
		}
743
		}
744
		REAL(xsxp)[ns] = s->x1;
744
		REAL(xsxp)[ns] = s->x1;
745
		REAL(ysxp)[ns] = s->y1;
745
		REAL(ysxp)[ns] = s->y1;
746
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_X, xsxp);
746
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_X, xsxp);
747
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_Y, ysxp);
747
		SET_VECTOR_ELT(ctr, CONTOUR_LIST_Y, ysxp);
748
		/*
748
		/*
749
		 * Set the names attribute for the contour
749
		 * Set the names attribute for the contour
750
		 * So that users can extract components using
750
		 * So that users can extract components using
751
		 * meaningful names
751
		 * meaningful names
752
		 */
752
		 */
753
		PROTECT(names = allocVector(STRSXP, 3));
753
		PROTECT(names = allocVector(STRSXP, 3));
754
		SET_STRING_ELT(names, 0, mkChar("level"));
754
		SET_STRING_ELT(names, 0, mkChar("level"));
755
		SET_STRING_ELT(names, 1, mkChar("x"));
755
		SET_STRING_ELT(names, 1, mkChar("x"));
756
		SET_STRING_ELT(names, 2, mkChar("y"));
756
		SET_STRING_ELT(names, 2, mkChar("y"));
757
		setAttrib(ctr, R_NamesSymbol, names);
757
		setAttrib(ctr, R_NamesSymbol, names);
758
		/*
758
		/*
759
		 * We're about to add another line to the list ...
759
		 * We're about to add another line to the list ...
760
		 */
760
		 */
761
		nlines += 1;
761
		nlines += 1;
762
		nc = LENGTH(VECTOR_ELT(container, 0));
762
		nc = LENGTH(VECTOR_ELT(container, 0));
763
		if (nlines == nc)
763
		if (nlines == nc)
764
		    /* Where does this get UNPROTECTed? */
764
		    /* Where does this get UNPROTECTed? */
765
		    SET_VECTOR_ELT(container, 0,
765
		    SET_VECTOR_ELT(container, 0,
766
				   growList(VECTOR_ELT(container, 0)));
766
				   growList(VECTOR_ELT(container, 0)));
767
		SET_VECTOR_ELT(VECTOR_ELT(container, 0), nlines - 1, ctr);
767
		SET_VECTOR_ELT(VECTOR_ELT(container, 0), nlines - 1, ctr);
768
		UNPROTECT(5);
768
		UNPROTECT(5);
769
	    }
769
	    }
770
	}
770
	}
771
    return nlines;
771
    return nlines;
772
}
772
}
773
 
773
 
774
/*
774
/*
775
 * Given nx x values, ny y values, nx*ny z values,
775
 * Given nx x values, ny y values, nx*ny z values,
776
 * and nl cut-values in z ...
776
 * and nl cut-values in z ...
777
 * ... produce a list of contour lines:
777
 * ... produce a list of contour lines:
778
 *   list of sub-lists
778
 *   list of sub-lists
779
 *     sub-list = x vector, y vector, and cut-value.
779
 *     sub-list = x vector, y vector, and cut-value.
780
 */
780
 */
781
SEXP GEcontourLines(double *x, int nx, double *y, int ny,
781
SEXP GEcontourLines(double *x, int nx, double *y, int ny,
782
		    double *z, double *levels, int nl)
782
		    double *z, double *levels, int nl)
783
{
783
{
784
    void *vmax;
784
    void *vmax;
785
    int i, nlines, len;
785
    int i, nlines, len;
786
    double atom, zmin, zmax;
786
    double atom, zmin, zmax;
787
    SEGP* segmentDB;
787
    SEGP* segmentDB;
788
    SEXP container, mainlist, templist;
788
    SEXP container, mainlist, templist;
789
    /*
789
    /*
790
     * "tie-breaker" values
790
     * "tie-breaker" values
791
     */
791
     */
792
    zmin = DBL_MAX;
792
    zmin = DBL_MAX;
793
    zmax = DBL_MIN;
793
    zmax = DBL_MIN;
794
    for (i = 0; i < nx * ny; i++)
794
    for (i = 0; i < nx * ny; i++)
795
	if (R_FINITE(z[i])) {
795
	if (R_FINITE(z[i])) {
796
	    if (zmax < z[i]) zmax =  z[i];
796
	    if (zmax < z[i]) zmax =  z[i];
797
	    if (zmin > z[i]) zmin =  z[i];
797
	    if (zmin > z[i]) zmin =  z[i];
798
	}
798
	}
799
 
799
 
800
    if (zmin >= zmax) {
800
    if (zmin >= zmax) {
801
	if (zmin == zmax)
801
	if (zmin == zmax)
802
	    warning(_("all z values are equal"));
802
	    warning(_("all z values are equal"));
803
	else
803
	else
804
	    warning(_("all z values are NA"));
804
	    warning(_("all z values are NA"));
805
	return R_NilValue;
805
	return R_NilValue;
806
    }
806
    }
807
    /* change to 1e-3, reconsidered because of PR#897
807
    /* change to 1e-3, reconsidered because of PR#897
808
     * but 1e-7, and even  2*DBL_EPSILON do not prevent inf.loop in contour().
808
     * but 1e-7, and even  2*DBL_EPSILON do not prevent inf.loop in contour().
809
     * maybe something like   16 * DBL_EPSILON * (..).
809
     * maybe something like   16 * DBL_EPSILON * (..).
810
     * see also max_contour_segments above */
810
     * see also max_contour_segments above */
811
    atom = 1e-3 * (zmax - zmin);
811
    atom = 1e-3 * (zmax - zmin);
812
    /*
812
    /*
813
     * Create a "container" which is a list with only 1 element.
813
     * Create a "container" which is a list with only 1 element.
814
     * The element is the list of lines that will be built up.
814
     * The element is the list of lines that will be built up.
815
     * I create the container because this allows me to PROTECT
815
     * I create the container because this allows me to PROTECT
816
     * the container once here and then UNPROTECT it at the end of
816
     * the container once here and then UNPROTECT it at the end of
817
     * this function and, as long as I always work with
817
     * this function and, as long as I always work with
818
     * VECTOR_ELT(container, 0) and SET_VECTOR_ELT(container, 0)
818
     * VECTOR_ELT(container, 0) and SET_VECTOR_ELT(container, 0)
819
     * in functions called from here, I don't need to worry about
819
     * in functions called from here, I don't need to worry about
820
     * protectin the list that I am building up.
820
     * protectin the list that I am building up.
821
     * Why bother?  Because the list I am building can potentially
821
     * Why bother?  Because the list I am building can potentially
822
     * grow and it's awkward to get the PROTECTs/UNPROTECTs right
822
     * grow and it's awkward to get the PROTECTs/UNPROTECTs right
823
     * when you're in a loop and growing a list.
823
     * when you're in a loop and growing a list.
824
     */
824
     */
825
    container = PROTECT(allocVector(VECSXP, 1));
825
    container = PROTECT(allocVector(VECSXP, 1));
826
    /*
826
    /*
827
     * Create "large" list (will trim excess at the end if necesary)
827
     * Create "large" list (will trim excess at the end if necesary)
828
     */
828
     */
829
    SET_VECTOR_ELT(container, 0, allocVector(VECSXP, CONTOUR_LIST_STEP));
829
    SET_VECTOR_ELT(container, 0, allocVector(VECSXP, CONTOUR_LIST_STEP));
830
    nlines = 0;
830
    nlines = 0;
831
    /*
831
    /*
832
     * Add lines for each contour level
832
     * Add lines for each contour level
833
     */
833
     */
834
    for (i = 0; i < nl; i++) {
834
    for (i = 0; i < nl; i++) {
835
	/*
835
	/*
836
	 * The vmaxget/set is to manage the memory that gets
836
	 * The vmaxget/set is to manage the memory that gets
837
	 * R_alloc'ed in the creation of the segmentDB structure
837
	 * R_alloc'ed in the creation of the segmentDB structure
838
	 */
838
	 */
839
	vmax = vmaxget();
839
	vmax = vmaxget();
840
	/*
840
	/*
841
	 * Generate a segment database
841
	 * Generate a segment database
842
	 */
842
	 */
843
	segmentDB = contourLines(x, nx, y, ny, z, levels[i], atom);
843
	segmentDB = contourLines(x, nx, y, ny, z, levels[i], atom);
844
	/*
844
	/*
845
	 * Add lines to the list based on the segment database
845
	 * Add lines to the list based on the segment database
846
	 */
846
	 */
847
	nlines = addContourLines(x, nx, y, ny, z, levels[i],
847
	nlines = addContourLines(x, nx, y, ny, z, levels[i],
848
				 atom, segmentDB, nlines,
848
				 atom, segmentDB, nlines,
849
				 container);
849
				 container);
850
	vmaxset(vmax);
850
	vmaxset(vmax);
851
    }
851
    }
852
    /*
852
    /*
853
     * Trim the list of lines to the appropriate length.
853
     * Trim the list of lines to the appropriate length.
854
     */
854
     */
855
    len = LENGTH(VECTOR_ELT(container, 0));
855
    len = LENGTH(VECTOR_ELT(container, 0));
856
    if (nlines < len) {
856
    if (nlines < len) {
857
	mainlist = VECTOR_ELT(container, 0);
857
	mainlist = VECTOR_ELT(container, 0);
858
	templist = PROTECT(allocVector(VECSXP, nlines));
858
	templist = PROTECT(allocVector(VECSXP, nlines));
859
	for (i=0; i<nlines; i++)
859
	for (i=0; i<nlines; i++)
860
	    SET_VECTOR_ELT(templist, i, VECTOR_ELT(mainlist, i));
860
	    SET_VECTOR_ELT(templist, i, VECTOR_ELT(mainlist, i));
861
	mainlist = templist;
861
	mainlist = templist;
862
	UNPROTECT(1);  /* UNPROTECT templist */
862
	UNPROTECT(1);  /* UNPROTECT templist */
863
    } else
863
    } else
864
	mainlist = VECTOR_ELT(container, 0);
864
	mainlist = VECTOR_ELT(container, 0);
865
    UNPROTECT(1);  /* UNPROTECT container */
865
    UNPROTECT(1);  /* UNPROTECT container */
866
    return mainlist;
866
    return mainlist;
867
}
867
}
868
 
868
 
869
SEXP attribute_hidden do_contourLines(SEXP call, SEXP op, SEXP args, SEXP env)
869
SEXP attribute_hidden do_contourLines(SEXP call, SEXP op, SEXP args, SEXP env)
870
{
870
{
871
    SEXP oargs, c, x, y, z;
871
    SEXP oargs, c, x, y, z;
872
    int nx, ny, nc;
872
    int nx, ny, nc;
873
 
873
 
874
    oargs = args;
874
    oargs = args;
875
 
875
 
876
    x = CAR(args);
876
    x = CAR(args);
877
    internalTypeCheck(call, x, REALSXP);
877
    internalTypeCheck(call, x, REALSXP);
878
    nx = LENGTH(x);
878
    nx = LENGTH(x);
879
    args = CDR(args);
879
    args = CDR(args);
880
 
880
 
881
    y = CAR(args);
881
    y = CAR(args);
882
    internalTypeCheck(call, y, REALSXP);
882
    internalTypeCheck(call, y, REALSXP);
883
    ny = LENGTH(y);
883
    ny = LENGTH(y);
884
    args = CDR(args);
884
    args = CDR(args);
885
 
885
 
886
    z = CAR(args);
886
    z = CAR(args);
887
    internalTypeCheck(call, z, REALSXP);
887
    internalTypeCheck(call, z, REALSXP);
888
    args = CDR(args);
888
    args = CDR(args);
889
 
889
 
890
    /* levels */
890
    /* levels */
891
    c = CAR(args);
891
    c = CAR(args);
892
    internalTypeCheck(call, c, REALSXP);
892
    internalTypeCheck(call, c, REALSXP);
893
    nc = LENGTH(c);
893
    nc = LENGTH(c);
894
    args = CDR(args);
894
    args = CDR(args);
895
 
895
 
896
    return GEcontourLines(REAL(x), nx, REAL(y), ny, REAL(z), REAL(c), nc);
896
    return GEcontourLines(REAL(x), nx, REAL(y), ny, REAL(z), REAL(c), nc);
897
}
897
}
898
 
898
 
899
/*
899
/*
900
 * The *base graphics* function contour() and the *general base*
900
 * The *base graphics* function contour() and the *general base*
901
 * function contourLines() use the same code to generate contour lines
901
 * function contourLines() use the same code to generate contour lines
902
 * (i.e., the function contourLines())
902
 * (i.e., the function contourLines())
903
 *
903
 *
904
 * I had a look at extracting the code that draws the labels
904
 * I had a look at extracting the code that draws the labels
905
 * into a *general base* function
905
 * into a *general base* function
906
 * (e.g., into some sort of labelLines() function),
906
 * (e.g., into some sort of labelLines() function),
907
 * but the code is too base-graphics-specific (e.g., one of the
907
 * but the code is too base-graphics-specific (e.g., one of the
908
 * labelling methods seeks the location closest to the edge of the
908
 * labelling methods seeks the location closest to the edge of the
909
 * plotting region) so I've left it alone for now.
909
 * plotting region) so I've left it alone for now.
910
 *
910
 *
911
 * This does mean that the contourLines() function is part of the
911
 * This does mean that the contourLines() function is part of the
912
 * graphics engine, but the contour() function is part of the
912
 * graphics engine, but the contour() function is part of the
913
 * base graphics system.
913
 * base graphics system.
914
 */
914
 */
915
 
915
 
916
static void contour(SEXP x, int nx, SEXP y, int ny, SEXP z,
916
static void contour(SEXP x, int nx, SEXP y, int ny, SEXP z,
917
		    double zc,
917
		    double zc,
918
		    SEXP labels, int cnum,
918
		    SEXP labels, int cnum,
919
		    Rboolean drawLabels, int method,
919
		    Rboolean drawLabels, int method,
920
		    Rboolean vectorFonts, int typeface, int fontindex,
920
		    Rboolean vectorFonts, int typeface, int fontindex,
921
		    double atom, DevDesc *dd)
921
		    double atom, DevDesc *dd)
922
{
922
{
923
/* draw a contour for one given contour level 'zc' */
923
/* draw a contour for one given contour level 'zc' */
924
 
924
 
925
    char *vmax;
925
    char *vmax;
926
 
926
 
927
    double xend, yend;
927
    double xend, yend;
928
    int i, ii, j, jj, ns, ns2, dir;
928
    int i, ii, j, jj, ns, ns2, dir;
929
    SEGP seglist, seg, s, start, end;
929
    SEGP seglist, seg, s, start, end;
930
    double *xxx, *yyy;
930
    double *xxx, *yyy;
931
 
931
 
932
    double variance, dX, dY, deltaX, deltaY;
932
    double variance, dX, dY, deltaX, deltaY;
933
    double dXC, dYC, deltaXC, deltaYC;
933
    double dXC, dYC, deltaXC, deltaYC;
934
    int range=0, indx=0, n; /* -Wall */
934
    int range=0, indx=0, n; /* -Wall */
935
    double lowestVariance;
935
    double lowestVariance;
936
    double squareSum, sum;
936
    double squareSum, sum;
937
    int iii, jjj;
937
    int iii, jjj;
938
    double distanceSum, labelDistance, avgGradient;
938
    double distanceSum, labelDistance, avgGradient;
939
    int zeroCount;
939
    int zeroCount;
940
    char buffer[255];
940
    char buffer[255];
941
    double avg;
941
    double avg;
942
    int result;
942
    int result;
943
    double ux, uy, vx, vy;
943
    double ux, uy, vx, vy;
944
    double xStart, yStart;
944
    double xStart, yStart;
945
    double dx, dy, dxy;
945
    double dx, dy, dxy;
946
    double labelHeight;
946
    double labelHeight;
947
    SEXP label1 = PROTECT(allocVector(REALSXP, 8));
947
    SEXP label1 = PROTECT(allocVector(REALSXP, 8));
948
    SEXP label2;
948
    SEXP label2;
949
    SEXP lab;
949
    SEXP lab;
950
    Rboolean gotLabel = FALSE;
950
    Rboolean gotLabel = FALSE;
951
    Rboolean ddl;/* Don't draw label -- currently unused, i.e. always FALSE*/
951
    Rboolean ddl;/* Don't draw label -- currently unused, i.e. always FALSE*/
952
 
952
 
953
#ifdef DEBUG_contour
953
#ifdef DEBUG_contour
954
    Rprintf("contour(lev = %g):\n", zc);
954
    Rprintf("contour(lev = %g):\n", zc);
955
#endif
955
#endif
956
 
956
 
957
    vmax = vmaxget();
957
    vmax = vmaxget();
958
    ctr_SegDB = contourLines(REAL(x), nx, REAL(y), ny, REAL(z), zc, atom);
958
    ctr_SegDB = contourLines(REAL(x), nx, REAL(y), ny, REAL(z), zc, atom);
959
    /* we need to keep ctr_SegDB available, so vmaxset(vmax); was wrong */
959
    /* we need to keep ctr_SegDB available, so vmaxset(vmax); was wrong */
960
 
960
 
961
    /* The segment database is now assembled. */
961
    /* The segment database is now assembled. */
962
    /* Begin following contours. */
962
    /* Begin following contours. */
963
    /* 1. Grab a segment */
963
    /* 1. Grab a segment */
964
    /* 2. Follow its tail */
964
    /* 2. Follow its tail */
965
    /* 3. Follow its head */
965
    /* 3. Follow its head */
966
    /* 4. Draw the contour */
966
    /* 4. Draw the contour */
967
 
967
 
968
    for (i = 0; i < nx - 1; i++)
968
    for (i = 0; i < nx - 1; i++)
969
      for (j = 0; j < ny - 1; j++) {
969
      for (j = 0; j < ny - 1; j++) {
970
	while ((seglist = ctr_SegDB[i + j * nx])) {
970
	while ((seglist = ctr_SegDB[i + j * nx])) {
971
	    ii = i; jj = j;
971
	    ii = i; jj = j;
972
	    start = end = seglist;
972
	    start = end = seglist;
973
	    ctr_SegDB[i + j * nx] = seglist->next;
973
	    ctr_SegDB[i + j * nx] = seglist->next;
974
	    xend = seglist->x1;
974
	    xend = seglist->x1;
975
	    yend = seglist->y1;
975
	    yend = seglist->y1;
976
	    while ((dir = ctr_segdir(xend, yend, REAL(x), REAL(y),
976
	    while ((dir = ctr_segdir(xend, yend, REAL(x), REAL(y),
977
				     &ii, &jj, nx, ny))) {
977
				     &ii, &jj, nx, ny))) {
978
		ctr_SegDB[ii + jj * nx]
978
		ctr_SegDB[ii + jj * nx]
979
		    = ctr_segupdate(xend, yend, dir, TRUE,/* = tail */
979
		    = ctr_segupdate(xend, yend, dir, TRUE,/* = tail */
980
				    ctr_SegDB[ii + jj * nx], &seg);
980
				    ctr_SegDB[ii + jj * nx], &seg);
981
		if (!seg) break;
981
		if (!seg) break;
982
		end->next = seg;
982
		end->next = seg;
983
		end = seg;
983
		end = seg;
984
		xend = end->x1;
984
		xend = end->x1;
985
		yend = end->y1;
985
		yend = end->y1;
986
	    }
986
	    }
987
	    end->next = NULL; /* <<< new for 1.2.3 */
987
	    end->next = NULL; /* <<< new for 1.2.3 */
988
	    ii = i; jj = j;
988
	    ii = i; jj = j;
989
	    xend = seglist->x0;
989
	    xend = seglist->x0;
990
	    yend = seglist->y0;
990
	    yend = seglist->y0;
991
	    while ((dir = ctr_segdir(xend, yend, REAL(x), REAL(y),
991
	    while ((dir = ctr_segdir(xend, yend, REAL(x), REAL(y),
992
				     &ii, &jj, nx, ny))) {
992
				     &ii, &jj, nx, ny))) {
993
		ctr_SegDB[ii + jj * nx]
993
		ctr_SegDB[ii + jj * nx]
994
		    = ctr_segupdate(xend, yend, dir, FALSE,/* ie. head */
994
		    = ctr_segupdate(xend, yend, dir, FALSE,/* ie. head */
995
				    ctr_SegDB[ii+jj*nx], &seg);
995
				    ctr_SegDB[ii+jj*nx], &seg);
996
		if (!seg) break;
996
		if (!seg) break;
997
		seg->next = start;
997
		seg->next = start;
998
		start = seg;
998
		start = seg;
999
		xend = start->x0;
999
		xend = start->x0;
1000
		yend = start->y0;
1000
		yend = start->y0;
1001
	    }
1001
	    }
1002
 
1002
 
1003
	    /* ns := #{segments of polyline} -- need to allocate */
1003
	    /* ns := #{segments of polyline} -- need to allocate */
1004
	    s = start;
1004
	    s = start;
1005
	    ns = 0;
1005
	    ns = 0;
1006
	    /* max_contour_segments: prevent inf.loop (shouldn't be needed) */
1006
	    /* max_contour_segments: prevent inf.loop (shouldn't be needed) */
1007
	    while (s && ns < max_contour_segments) {
1007
	    while (s && ns < max_contour_segments) {
1008
		ns++;
1008
		ns++;
1009
		s = s->next;
1009
		s = s->next;
1010
	    }
1010
	    }
1011
	    if(ns == max_contour_segments)
1011
	    if(ns == max_contour_segments)
1012
		warning(_("contour(): circular/long seglist -- bug.report()!"));
1012
		warning(_("contour(): circular/long seglist -- bug.report()!"));
1013
 
1013
 
1014
	    /* countour midpoint : use for labelling sometime (not yet!) */
1014
	    /* countour midpoint : use for labelling sometime (not yet!) */
1015
	    if (ns > 3) ns2 = ns/2; else ns2 = -1;
1015
	    if (ns > 3) ns2 = ns/2; else ns2 = -1;
1016
 
1016
 
1017
	    vmax = vmaxget();
1017
	    vmax = vmaxget();
1018
	    xxx = (double *) R_alloc(ns + 1, sizeof(double));
1018
	    xxx = (double *) R_alloc(ns + 1, sizeof(double));
1019
	    yyy = (double *) R_alloc(ns + 1, sizeof(double));
1019
	    yyy = (double *) R_alloc(ns + 1, sizeof(double));
1020
	    /* now have the space, go through again: */
1020
	    /* now have the space, go through again: */
1021
	    s = start;
1021
	    s = start;
1022
	    ns = 0;
1022
	    ns = 0;
1023
	    xxx[ns] = s->x0;
1023
	    xxx[ns] = s->x0;
1024
	    yyy[ns++] = s->y0;
1024
	    yyy[ns++] = s->y0;
1025
	    while (s->next && ns < max_contour_segments) {
1025
	    while (s->next && ns < max_contour_segments) {
1026
		s = s->next;
1026
		s = s->next;
1027
		xxx[ns] = s->x0;
1027
		xxx[ns] = s->x0;
1028
		yyy[ns++] = s->y0;
1028
		yyy[ns++] = s->y0;
1029
	    }
1029
	    }
1030
	    xxx[ns] = s->x1;
1030
	    xxx[ns] = s->x1;
1031
	    yyy[ns++] = s->y1;
1031
	    yyy[ns++] = s->y1;
1032
#ifdef DEBUG_contour
1032
#ifdef DEBUG_contour
1033
	    Rprintf("  [%2d,%2d]: (x,y)[1:%d] = ", i,j, ns);
1033
	    Rprintf("  [%2d,%2d]: (x,y)[1:%d] = ", i,j, ns);
1034
	    if(ns >= 5)
1034
	    if(ns >= 5)
1035
		Rprintf(" (%g,%g), (%g,%g), ..., (%g,%g)\n",
1035
		Rprintf(" (%g,%g), (%g,%g), ..., (%g,%g)\n",
1036
			xxx[0],yyy[0], xxx[1],yyy[1], xxx[ns-1],yyy[ns-1]);
1036
			xxx[0],yyy[0], xxx[1],yyy[1], xxx[ns-1],yyy[ns-1]);
1037
	    else
1037
	    else
1038
		for(iii = 0; iii < ns; iii++)
1038
		for(iii = 0; iii < ns; iii++)
1039
		    Rprintf(" (%g,%g)%s", xxx[iii],yyy[iii],
1039
		    Rprintf(" (%g,%g)%s", xxx[iii],yyy[iii],
1040
			    (iii < ns-1) ? "," : "\n");
1040
			    (iii < ns-1) ? "," : "\n");
1041
#endif
1041
#endif
1042
 
1042
 
1043
	    GMode(1, dd);
1043
	    GMode(1, dd);
1044
 
1044
 
1045
	    if (drawLabels) {
1045
	    if (drawLabels) {
1046
		/* If user supplied labels, use i'th one of them
1046
		/* If user supplied labels, use i'th one of them
1047
		   Otherwise stringify the z-value of the contour */
1047
		   Otherwise stringify the z-value of the contour */
1048
		buffer[0] = ' ';
1048
		buffer[0] = ' ';
1049
		if (!isNull(labels)) {
1049
		if (!isNull(labels)) {
1050
		    int numl = length(labels);
1050
		    int numl = length(labels);
1051
		    strcpy(&buffer[1], 
1051
		    strcpy(&buffer[1], 
1052
			   translateChar(STRING_ELT(labels, cnum % numl)));
1052
			   translateChar(STRING_ELT(labels, cnum % numl)));
1053
		}
1053
		}
1054
		else {
1054
		else {
1055
		    PROTECT(lab = allocVector(REALSXP, 1));
1055
		    PROTECT(lab = allocVector(REALSXP, 1));
1056
		    REAL(lab)[0] = zc;
1056
		    REAL(lab)[0] = zc;
1057
		    lab = labelformat(lab);
1057
		    lab = labelformat(lab);
1058
		    strcpy(&buffer[1], CHAR(STRING_ELT(lab, 0))); /* ASCII */
1058
		    strcpy(&buffer[1], CHAR(STRING_ELT(lab, 0))); /* ASCII */
1059
		    UNPROTECT(1);
1059
		    UNPROTECT(1);
1060
		}
1060
		}
1061
		buffer[strlen(buffer)+1] = '\0';
1061
		buffer[strlen(buffer)+1] = '\0';
1062
		buffer[strlen(buffer)] = ' ';
1062
		buffer[strlen(buffer)] = ' ';
1063
 
1063
 
1064
		if (vectorFonts) {
1064
		if (vectorFonts) {
1065
		    /* 1, 1 => sans serif, basic font */
1065
		    /* 1, 1 => sans serif, basic font */
1066
		    labelDistance =
1066
		    labelDistance =
1067
			GVStrWidth(buffer, typeface,
1067
			GVStrWidth(buffer, typeface,
1068
				   fontindex, INCHES, dd);
1068
				   fontindex, INCHES, dd);
1069
		    labelHeight =
1069
		    labelHeight =
1070
			GVStrHeight(buffer, typeface,
1070
			GVStrHeight(buffer, typeface,
1071
				    fontindex, INCHES, dd);
1071
				    fontindex, INCHES, dd);
1072
		}
1072
		}
1073
		else {
1073
		else {
1074
		    labelDistance = GStrWidth(buffer, INCHES, dd);
1074
		    labelDistance = GStrWidth(buffer, INCHES, dd);
1075
		    labelHeight = GStrHeight(buffer, INCHES, dd);
1075
		    labelHeight = GStrHeight(buffer, INCHES, dd);
1076
		}
1076
		}
1077
 
1077
 
1078
		if (labelDistance > 0) {
1078
		if (labelDistance > 0) {
1079
		    /* Try to find somewhere to draw the label */
1079
		    /* Try to find somewhere to draw the label */
1080
		    switch (method) {
1080
		    switch (method) {
1081
		    case 0: /* draw label at one end of contour
1081
		    case 0: /* draw label at one end of contour
1082
			       overwriting contour line
1082
			       overwriting contour line
1083
			    */
1083
			    */
1084
			if (useStart(xxx, yyy, ns, dd) )
1084
			if (useStart(xxx, yyy, ns, dd) )
1085
			    indx = 0;
1085
			    indx = 0;
1086
			else
1086
			else
1087
			    indx = ns - 1;
1087
			    indx = ns - 1;
1088
			break;
1088
			break;
1089
		    case 1: /* draw label at one end of contour
1089
		    case 1: /* draw label at one end of contour
1090
			       embedded in contour
1090
			       embedded in contour
1091
			       no overlapping labels
1091
			       no overlapping labels
1092
			    */
1092
			    */
1093
			indx = 0;
1093
			indx = 0;
1094
			range = 0;
1094
			range = 0;
1095
			gotLabel = FALSE;
1095
			gotLabel = FALSE;
1096
			if (useStart(xxx, yyy, ns, dd)) {
1096
			if (useStart(xxx, yyy, ns, dd)) {
1097
			    iii = 0;
1097
			    iii = 0;
1098
			    n = findGapUp(xxx, yyy, ns, labelDistance, dd);
1098
			    n = findGapUp(xxx, yyy, ns, labelDistance, dd);
1099
			}
1099
			}
1100
			else {
1100
			else {
1101
			    n = findGapDown(xxx, yyy, ns, labelDistance, dd);
1101
			    n = findGapDown(xxx, yyy, ns, labelDistance, dd);
1102
			    iii = ns - n - 1;
1102
			    iii = ns - n - 1;
1103
			}
1103
			}
1104
			if (n > 0) {
1104
			if (n > 0) {
1105
			    /** Find 4 corners of label extents **/
1105
			    /** Find 4 corners of label extents **/
1106
			    FindCorners(labelDistance, labelHeight, label1,
1106
			    FindCorners(labelDistance, labelHeight, label1,
1107
					xxx[iii], yyy[iii],
1107
					xxx[iii], yyy[iii],
1108
					xxx[iii+n], yyy[iii+n], dd);
1108
					xxx[iii+n], yyy[iii+n], dd);
1109
 
1109
 
1110
			    /** Test corners for intersection with previous labels **/
1110
			    /** Test corners for intersection with previous labels **/
1111
			    label2 = labelList;
1111
			    label2 = labelList;
1112
			    result = 0;
1112
			    result = 0;
1113
			    while ((result == 0) && (label2 != R_NilValue)) {
1113
			    while ((result == 0) && (label2 != R_NilValue)) {
1114
				result = TestLabelIntersection(label1, CAR(label2));
1114
				result = TestLabelIntersection(label1, CAR(label2));
1115
				label2 = CDR(label2);
1115
				label2 = CDR(label2);
1116
			    }
1116
			    }
1117
			    if (result == 0) {
1117
			    if (result == 0) {
1118
				result = LabelInsideWindow(label1, dd);
1118
				result = LabelInsideWindow(label1, dd);
1119
				if (result == 0) {
1119
				if (result == 0) {
1120
				    indx = iii;
1120
				    indx = iii;
1121
				    range = n;
1121
				    range = n;
1122
				    gotLabel = TRUE;
1122
				    gotLabel = TRUE;
1123
				}
1123
				}
1124
			    }
1124
			    }
1125
			}
1125
			}
1126
			break;
1126
			break;
1127
		    case 2: /* draw label on flattest portion of contour
1127
		    case 2: /* draw label on flattest portion of contour
1128
			       embedded in contour line
1128
			       embedded in contour line
1129
			       no overlapping labels
1129
			       no overlapping labels
1130
			    */
1130
			    */
1131
			/* Look for flatest sequence of contour gradients */
1131
			/* Look for flatest sequence of contour gradients */
1132
			lowestVariance = 9999999;   /* A large number */
1132
			lowestVariance = 9999999;   /* A large number */
1133
			indx = 0;
1133
			indx = 0;
1134
			range = 0;
1134
			range = 0;
1135
			gotLabel = FALSE;
1135
			gotLabel = FALSE;
1136
			for (iii = 0; iii < ns; iii++) {
1136
			for (iii = 0; iii < ns; iii++) {
1137
			    distanceSum = 0;
1137
			    distanceSum = 0;
1138
			    avgGradient = 0;
1138
			    avgGradient = 0;
1139
			    squareSum = 0;
1139
			    squareSum = 0;
1140
			    sum = 0;
1140
			    sum = 0;
1141
			    n = 0;
1141
			    n = 0;
1142
			    zeroCount = 0;
1142
			    zeroCount = 0;
1143
			    jjj = (iii + 1);
1143
			    jjj = (iii + 1);
1144
			    while ((jjj < ns-1) &&
1144
			    while ((jjj < ns-1) &&
1145
				   (distanceSum < labelDistance)) {
1145
				   (distanceSum < labelDistance)) {
1146
 
1146
 
1147
				/* Find a gap big enough for the label
1147
				/* Find a gap big enough for the label
1148
				   use several segments if necessary
1148
				   use several segments if necessary
1149
				*/
1149
				*/
1150
				dX = xxx[jjj] - xxx[jjj - n - 1];
1150
				dX = xxx[jjj] - xxx[jjj - n - 1];
1151
				dY = yyy[jjj] - yyy[jjj - n - 1];
1151
				dY = yyy[jjj] - yyy[jjj - n - 1];
1152
				dXC = GConvertXUnits(dX, USER, INCHES, dd);
1152
				dXC = GConvertXUnits(dX, USER, INCHES, dd);
1153
				dYC = GConvertYUnits(dY, USER, INCHES, dd);
1153
				dYC = GConvertYUnits(dY, USER, INCHES, dd);
1154
				distanceSum = hypot(dXC, dYC);
1154
				distanceSum = hypot(dXC, dYC);
1155
 
1155
 
1156
				/* Calculate the variance of the gradients
1156
				/* Calculate the variance of the gradients
1157
				   of the segments that will make way for the
1157
				   of the segments that will make way for the
1158
				   label
1158
				   label
1159
				*/
1159
				*/
1160
				deltaX = xxx[jjj] - xxx[jjj - 1];
1160
				deltaX = xxx[jjj] - xxx[jjj - 1];
1161
				deltaY = yyy[jjj] - yyy[jjj - 1];
1161
				deltaY = yyy[jjj] - yyy[jjj - 1];
1162
				deltaXC = GConvertXUnits(deltaX, USER, INCHES, dd);
1162
				deltaXC = GConvertXUnits(deltaX, USER, INCHES, dd);
1163
				deltaYC = GConvertYUnits(deltaY, USER, INCHES, dd);
1163
				deltaYC = GConvertYUnits(deltaY, USER, INCHES, dd);
1164
				if (deltaX == 0) {deltaX = 1;}
1164
				if (deltaX == 0) {deltaX = 1;}
1165
				avgGradient += (deltaY/deltaX);
1165
				avgGradient += (deltaY/deltaX);
1166
				squareSum += avgGradient * avgGradient;
1166
				squareSum += avgGradient * avgGradient;
1167
				jjj = (jjj + 1);
1167
				jjj = (jjj + 1);
1168
				n += 1;
1168
				n += 1;
1169
			    }
1169
			    }
1170
			    if (distanceSum < labelDistance)
1170
			    if (distanceSum < labelDistance)
1171
				break;
1171
				break;
1172
 
1172
 
1173
			    /** Find 4 corners of label extents **/
1173
			    /** Find 4 corners of label extents **/
1174
			    FindCorners(labelDistance, labelHeight, label1,
1174
			    FindCorners(labelDistance, labelHeight, label1,
1175
					xxx[iii], yyy[iii],
1175
					xxx[iii], yyy[iii],
1176
					xxx[iii+n], yyy[iii+n], dd);
1176
					xxx[iii+n], yyy[iii+n], dd);
1177
 
1177
 
1178
			    /** Test corners for intersection with previous labels **/
1178
			    /** Test corners for intersection with previous labels **/
1179
			    label2 = labelList;
1179
			    label2 = labelList;
1180
			    result = 0;
1180
			    result = 0;
1181
			    while ((result == 0) && (label2 != R_NilValue)) {
1181
			    while ((result == 0) && (label2 != R_NilValue)) {
1182
				result = TestLabelIntersection(label1, CAR(label2));
1182
				result = TestLabelIntersection(label1, CAR(label2));
1183
				label2 = CDR(label2);
1183
				label2 = CDR(label2);
1184
			    }
1184
			    }
1185
			    if (result == 0)
1185
			    if (result == 0)
1186
				result = LabelInsideWindow(label1, dd);
1186
				result = LabelInsideWindow(label1, dd);
1187
			    if (result == 0) {
1187
			    if (result == 0) {
1188
				variance = (squareSum - (avgGradient * avgGradient) / n) / n;
1188
				variance = (squareSum - (avgGradient * avgGradient) / n) / n;
1189
				avgGradient /= n;
1189
				avgGradient /= n;
1190
				if (variance < lowestVariance) {
1190
				if (variance < lowestVariance) {
1191
				    lowestVariance = variance;
1191
				    lowestVariance = variance;
1192
				    indx = iii;
1192
				    indx = iii;
1193
				    range = n;
1193
				    range = n;
1194
				    avg = avgGradient;
1194
				    avg = avgGradient;
1195
				}
1195
				}
1196
			    }
1196
			    }
1197
			    if (lowestVariance < 9999999)
1197
			    if (lowestVariance < 9999999)
1198
				gotLabel = TRUE;
1198
				gotLabel = TRUE;
1199
			}
1199
			}
1200
		    } /* switch (method) */
1200
		    } /* switch (method) */
1201
 
1201
 
1202
		    if (method == 0) {
1202
		    if (method == 0) {
1203
			GPolyline(ns, xxx, yyy, USER, dd);
1203
			GPolyline(ns, xxx, yyy, USER, dd);
1204
			if (vectorFonts)
1204
			if (vectorFonts)
1205
			    GVText(xxx[indx], yyy[indx], USER, buffer,
1205
			    GVText(xxx[indx], yyy[indx], USER, buffer,
1206
				   typeface, fontindex,
1206
				   typeface, fontindex,
1207
				   .5, .5, 0, dd);
1207
				   .5, .5, 0, dd);
1208
			else
1208
			else
1209
			    GText(xxx[indx], yyy[indx], USER, buffer,
1209
			    GText(xxx[indx], yyy[indx], USER, buffer,
1210
				  .5, .5, 0, dd);
1210
				  .5, .5, 0, dd);
1211
		    }
1211
		    }
1212
		    else {
1212
		    else {
1213
			for (iii = 0; iii < indx; iii++)
1213
			for (iii = 0; iii < indx; iii++)
1214
			    GLine(xxx[iii], yyy[iii],
1214
			    GLine(xxx[iii], yyy[iii],
1215
				  xxx[iii+1], yyy[iii+1], USER, dd);
1215
				  xxx[iii+1], yyy[iii+1], USER, dd);
1216
			for (iii = indx+range; iii < ns - 1; iii++)
1216
			for (iii = indx+range; iii < ns - 1; iii++)
1217
			    GLine(xxx[iii], yyy[iii],
1217
			    GLine(xxx[iii], yyy[iii],
1218
				  xxx[iii+1], yyy[iii+1], USER, dd);
1218
				  xxx[iii+1], yyy[iii+1], USER, dd);
1219
 
1219
 
1220
			if (gotLabel) {
1220
			if (gotLabel) {
1221
			    /* find which plot edge we are closest to */
1221
			    /* find which plot edge we are closest to */
1222
			    int closest; /* 0 = indx,  1 = indx+range */
1222
			    int closest; /* 0 = indx,  1 = indx+range */
1223
			    double dx1, dx2, dy1, dy2, dmin;
1223
			    double dx1, dx2, dy1, dy2, dmin;
1224
			    dx1 = fmin2((xxx[indx] - Rf_gpptr(dd)->usr[0]),
1224
			    dx1 = fmin2((xxx[indx] - Rf_gpptr(dd)->usr[0]),
1225
					(Rf_gpptr(dd)->usr[1] - xxx[indx]));
1225
					(Rf_gpptr(dd)->usr[1] - xxx[indx]));
1226
			    dx2 = fmin2((Rf_gpptr(dd)->usr[1] - xxx[indx+range]),
1226
			    dx2 = fmin2((Rf_gpptr(dd)->usr[1] - xxx[indx+range]),
1227
					(xxx[indx+range] - Rf_gpptr(dd)->usr[0]));
1227
					(xxx[indx+range] - Rf_gpptr(dd)->usr[0]));
1228
			    if (dx1 < dx2) {
1228
			    if (dx1 < dx2) {
1229
				closest = 0;
1229
				closest = 0;
1230
				dmin = dx1;
1230
				dmin = dx1;
1231
			    } else {
1231
			    } else {
1232
				closest = 1;
1232
				closest = 1;
1233
				dmin = dx2;
1233
				dmin = dx2;
1234
			    }
1234
			    }
1235
			    dy1 = fmin2((yyy[indx] - Rf_gpptr(dd)->usr[2]),
1235
			    dy1 = fmin2((yyy[indx] - Rf_gpptr(dd)->usr[2]),
1236
					(Rf_gpptr(dd)->usr[3] - yyy[indx]));
1236
					(Rf_gpptr(dd)->usr[3] - yyy[indx]));
1237
			    if (closest && (dy1 < dmin)) {
1237
			    if (closest && (dy1 < dmin)) {
1238
				closest = 0;
1238
				closest = 0;
1239
				dmin = dy1;
1239
				dmin = dy1;
1240
			    } else if (dy1 < dmin)
1240
			    } else if (dy1 < dmin)
1241
				dmin = dy1;
1241
				dmin = dy1;
1242
			    dy2 = fmin2((Rf_gpptr(dd)->usr[3] - yyy[indx+range]),
1242
			    dy2 = fmin2((Rf_gpptr(dd)->usr[3] - yyy[indx+range]),
1243
					(yyy[indx+range] - Rf_gpptr(dd)->usr[2]));
1243
					(yyy[indx+range] - Rf_gpptr(dd)->usr[2]));
1244
			    if (!closest && (dy2 < dmin))
1244
			    if (!closest && (dy2 < dmin))
1245
				closest = 1;
1245
				closest = 1;
1246
 
1246
 
1247
			    dx = GConvertXUnits(xxx[indx+range] - xxx[indx],
1247
			    dx = GConvertXUnits(xxx[indx+range] - xxx[indx],
1248
						USER, INCHES, dd);
1248
						USER, INCHES, dd);
1249
			    dy = GConvertYUnits(yyy[indx+range] - yyy[indx],
1249
			    dy = GConvertYUnits(yyy[indx+range] - yyy[indx],
1250
						USER, INCHES, dd);
1250
						USER, INCHES, dd);
1251
			    dxy = hypot(dx, dy);
1251
			    dxy = hypot(dx, dy);
1252
 
1252
 
1253
			    /* save the current label for checking overlap */
1253
			    /* save the current label for checking overlap */
1254
			    label2 = allocVector(REALSXP, 8);
1254
			    label2 = allocVector(REALSXP, 8);
1255
 
1255
 
1256
			    FindCorners(labelDistance, labelHeight, label2,
1256
			    FindCorners(labelDistance, labelHeight, label2,
1257
					xxx[indx], yyy[indx],
1257
					xxx[indx], yyy[indx],
1258
					xxx[indx+range], yyy[indx+range], dd);
1258
					xxx[indx+range], yyy[indx+range], dd);
1259
			    UNPROTECT_PTR(labelList);
1259
			    UNPROTECT_PTR(labelList);
1260
			    labelList = PROTECT(CONS(label2, labelList));
1260
			    labelList = PROTECT(CONS(label2, labelList));
1261
 
1261
 
1262
			    ddl = FALSE;
1262
			    ddl = FALSE;
1263
			    /* draw an extra bit of segment if the label
1263
			    /* draw an extra bit of segment if the label
1264
			       doesn't fill the gap */
1264
			       doesn't fill the gap */
1265
			    if (closest) {
1265
			    if (closest) {
1266
				xStart = xxx[indx+range] -
1266
				xStart = xxx[indx+range] -
1267
				    (xxx[indx+range] - xxx[indx]) *
1267
				    (xxx[indx+range] - xxx[indx]) *
1268
				    labelDistance / dxy;
1268
				    labelDistance / dxy;
1269
				yStart = yyy[indx+range] -
1269
				yStart = yyy[indx+range] -
1270
				    (yyy[indx+range] - yyy[indx]) *
1270
				    (yyy[indx+range] - yyy[indx]) *
1271
				    labelDistance / dxy;
1271
				    labelDistance / dxy;
1272
				if (labelDistance / dxy < 1)
1272
				if (labelDistance / dxy < 1)
1273
				    GLine(xxx[indx], yyy[indx],
1273
				    GLine(xxx[indx], yyy[indx],
1274
					  xStart, yStart,
1274
					  xStart, yStart,
1275
					  USER, dd);
1275
					  USER, dd);
1276
			    } else {
1276
			    } else {
1277
				xStart = xxx[indx] +
1277
				xStart = xxx[indx] +
1278
				    (xxx[indx+range] - xxx[indx]) *
1278
				    (xxx[indx+range] - xxx[indx]) *
1279
				    labelDistance / dxy;
1279
				    labelDistance / dxy;
1280
				yStart = yyy[indx] +
1280
				yStart = yyy[indx] +
1281
				    (yyy[indx+range] - yyy[indx]) *
1281
				    (yyy[indx+range] - yyy[indx]) *
1282
				    labelDistance / dxy;
1282
				    labelDistance / dxy;
1283
				if (labelDistance / dxy < 1)
1283
				if (labelDistance / dxy < 1)
1284
				    GLine(xStart, yStart,
1284
				    GLine(xStart, yStart,
1285
					  xxx[indx+range], yyy[indx+range],
1285
					  xxx[indx+range], yyy[indx+range],
1286
					  USER, dd);
1286
					  USER, dd);
1287
			    }
1287
			    }
1288
 
1288
 
1289
			    /*** Draw contour labels ***/
1289
			    /*** Draw contour labels ***/
1290
			    if (xxx[indx] < xxx[indx+range]) {
1290
			    if (xxx[indx] < xxx[indx+range]) {
1291
				if (closest) {
1291
				if (closest) {
1292
				    ux = xStart;
1292
				    ux = xStart;
1293
				    uy = yStart;
1293
				    uy = yStart;
1294
				    vx = xxx[indx+range];
1294
				    vx = xxx[indx+range];
1295
				    vy = yyy[indx+range];
1295
				    vy = yyy[indx+range];
1296
				} else {
1296
				} else {
1297
				    ux = xxx[indx];
1297
				    ux = xxx[indx];
1298
				    uy = yyy[indx];
1298
				    uy = yyy[indx];
1299
				    vx = xStart;
1299
				    vx = xStart;
1300
				    vy = yStart;
1300
				    vy = yStart;
1301
				}
1301
				}
1302
			    }
1302
			    }
1303
			    else {
1303
			    else {
1304
				if (closest) {
1304
				if (closest) {
1305
				    ux = xxx[indx+range];
1305
				    ux = xxx[indx+range];
1306
				    uy = yyy[indx+range];
1306
				    uy = yyy[indx+range];
1307
				    vx = xStart;
1307
				    vx = xStart;
1308
				    vy = yStart;
1308
				    vy = yStart;
1309
				} else {
1309
				} else {
1310
				    ux = xStart;
1310
				    ux = xStart;
1311
				    uy = yStart;
1311
				    uy = yStart;
1312
				    vx = xxx[indx];
1312
				    vx = xxx[indx];
1313
				    vy = yyy[indx];
1313
				    vy = yyy[indx];
1314
				}
1314
				}
1315
			    }
1315
			    }
1316
 
1316
 
1317
			    if (!ddl) {
1317
			    if (!ddl) {
1318
				/* convert to INCHES for calculation of
1318
				/* convert to INCHES for calculation of
1319
				   angle to draw text
1319
				   angle to draw text
1320
				*/
1320
				*/
1321
				GConvert(&ux, &uy, USER, INCHES, dd);
1321
				GConvert(&ux, &uy, USER, INCHES, dd);
1322
				GConvert(&vx, &vy, USER, INCHES, dd);
1322
				GConvert(&vx, &vy, USER, INCHES, dd);
1323
				/* 1, 1 => sans serif, basic font
1323
				/* 1, 1 => sans serif, basic font
1324
				   0, .5 => left, centre justified */
1324
				   0, .5 => left, centre justified */
1325
				if (vectorFonts)
1325
				if (vectorFonts)
1326
				    GVText(ux, uy, INCHES, buffer,
1326
				    GVText(ux, uy, INCHES, buffer,
1327
					   typeface, fontindex, 0, .5,
1327
					   typeface, fontindex, 0, .5,
1328
					   (180 / 3.14) * atan2(vy - uy, vx - ux),
1328
					   (180 / 3.14) * atan2(vy - uy, vx - ux),
1329
					   dd);
1329
					   dd);
1330
				else
1330
				else
1331
				    GText (ux, uy, INCHES, buffer, 0, .5,
1331
				    GText (ux, uy, INCHES, buffer, 0, .5,
1332
					   (180 / 3.14) * atan2(vy - uy, vx - ux),
1332
					   (180 / 3.14) * atan2(vy - uy, vx - ux),
1333
					   dd);
1333
					   dd);
1334
			    }
1334
			    }
1335
			} /* if (gotLabel) */
1335
			} /* if (gotLabel) */
1336
		    } /* if (method == 0) else ... */
1336
		    } /* if (method == 0) else ... */
1337
		} /* if (labelDistance > 0) */
1337
		} /* if (labelDistance > 0) */
1338
 
1338
 
1339
	    } /* if (drawLabels) */
1339
	    } /* if (drawLabels) */
1340
	    else {
1340
	    else {
1341
		GPolyline(ns, xxx, yyy, USER, dd);
1341
		GPolyline(ns, xxx, yyy, USER, dd);
1342
	    }
1342
	    }
1343
 
1343
 
1344
	    GMode(0, dd);
1344
	    GMode(0, dd);
1345
	    vmaxset(vmax);
1345
	    vmaxset(vmax);
1346
	} /* while */
1346
	} /* while */
1347
      } /* for(i .. )  for(j ..) */
1347
      } /* for(i .. )  for(j ..) */
1348
    vmaxset(vmax); /* now we are done with ctr_SegDB */
1348
    vmaxset(vmax); /* now we are done with ctr_SegDB */
1349
    UNPROTECT_PTR(label1); /* pwwwargh! This is messy, but last thing
1349
    UNPROTECT_PTR(label1); /* pwwwargh! This is messy, but last thing
1350
			      protected is likely labelList, and that needs
1350
			      protected is likely labelList, and that needs
1351
			      to be preserved across calls */
1351
			      to be preserved across calls */
1352
}
1352
}
1353
 
1353
 
1354
/* contour(x, y, z, levels, labels, labcex, drawlabels,
1354
/* contour(x, y, z, levels, labels, labcex, drawlabels,
1355
 *         method, vfont, col = col, lty = lty, lwd = lwd)
1355
 *         method, vfont, col = col, lty = lty, lwd = lwd)
1356
 */
1356
 */
1357
SEXP attribute_hidden do_contour(SEXP call, SEXP op, SEXP args, SEXP env)
1357
SEXP attribute_hidden do_contour(SEXP call, SEXP op, SEXP args, SEXP env)
1358
{
1358
{
1359
    SEXP oargs, c, x, y, z, vfont, col, rawcol, lty, lwd, labels;
1359
    SEXP oargs, c, x, y, z, vfont, col, rawcol, lty, lwd, labels;
1360
    int i, j, nx, ny, nc, ncol, nlty, nlwd;
1360
    int i, j, nx, ny, nc, ncol, nlty, nlwd;
1361
    int ltysave, colsave, lwdsave;
1361
    int ltysave, colsave, lwdsave;
1362
    double cexsave;
1362
    double cexsave;
1363
    double atom, zmin, zmax;
1363
    double atom, zmin, zmax;
1364
    char *vmax, *vmax0;
1364
    char *vmax, *vmax0;
1365
    int method;
1365
    int method;
1366
    Rboolean drawLabels;
1366
    Rboolean drawLabels;
1367
    Rboolean vectorFonts = FALSE;
1367
    Rboolean vectorFonts = FALSE;
1368
    int typeface = 0;
1368
    int typeface = 0;
1369
    int fontindex = 0;
1369
    int fontindex = 0;
1370
    double labcex;
1370
    double labcex;
1371
    DevDesc *dd = CurrentDevice();
1371
    DevDesc *dd = CurrentDevice();
1372
    SEXP result = R_NilValue;
1372
    SEXP result = R_NilValue;
1373
 
1373
 
1374
    GCheckState(dd);
1374
    GCheckState(dd);
1375
 
1375
 
1376
    if (length(args) < 4)
1376
    if (length(args) < 4)
1377
	error(_("too few arguments"));
1377
	error(_("too few arguments"));
1378
 
1378
 
1379
    oargs = args;
1379
    oargs = args;
1380
 
1380
 
1381
    x = CAR(args);
1381
    x = CAR(args);
1382
    internalTypeCheck(call, x, REALSXP);
1382
    internalTypeCheck(call, x, REALSXP);
1383
    nx = LENGTH(x);
1383
    nx = LENGTH(x);
1384
    args = CDR(args);
1384
    args = CDR(args);
1385
 
1385
 
1386
    y = CAR(args);
1386
    y = CAR(args);
1387
    internalTypeCheck(call, y, REALSXP);
1387
    internalTypeCheck(call, y, REALSXP);
1388
    ny = LENGTH(y);
1388
    ny = LENGTH(y);
1389
    args = CDR(args);
1389
    args = CDR(args);
1390
 
1390
 
1391
    z = CAR(args);
1391
    z = CAR(args);
1392
    internalTypeCheck(call, z, REALSXP);
1392
    internalTypeCheck(call, z, REALSXP);
1393
    args = CDR(args);
1393
    args = CDR(args);
1394
 
1394
 
1395
    /* levels */
1395
    /* levels */
1396
    c = CAR(args);
1396
    c = CAR(args);
1397
    internalTypeCheck(call, c, REALSXP);
1397
    internalTypeCheck(call, c, REALSXP);
1398
    nc = LENGTH(c);
1398
    nc = LENGTH(c);
1399
    args = CDR(args);
1399
    args = CDR(args);
1400
 
1400
 
1401
    labels = CAR(args);
1401
    labels = CAR(args);
1402
    if (!isNull(labels))
1402
    if (!isNull(labels))
1403
	internalTypeCheck(call, labels, STRSXP);
1403
	internalTypeCheck(call, labels, STRSXP);
1404
    args = CDR(args);
1404
    args = CDR(args);
1405
 
1405
 
1406
    labcex = asReal(CAR(args));
1406
    labcex = asReal(CAR(args));
1407
    args = CDR(args);
1407
    args = CDR(args);
1408
 
1408
 
1409
    drawLabels = (Rboolean)asLogical(CAR(args));
1409
    drawLabels = (Rboolean)asLogical(CAR(args));
1410
    args = CDR(args);
1410
    args = CDR(args);
1411
 
1411
 
1412
    method = asInteger(CAR(args)); args = CDR(args);
1412
    method = asInteger(CAR(args)); args = CDR(args);
1413
    if (method < 1 || method > 3)
1413
    if (method < 1 || method > 3)
1414
	error(_("invalid '%s' value"), "method");
1414
	error(_("invalid '%s' value"), "method");
1415
 
1415
 
1416
    PROTECT(vfont = FixupVFont(CAR(args)));
1416
    PROTECT(vfont = FixupVFont(CAR(args)));
1417
    if (!isNull(vfont)) {
1417
    if (!isNull(vfont)) {
1418
	vectorFonts = TRUE;
1418
	vectorFonts = TRUE;
1419
	typeface = INTEGER(vfont)[0];
1419
	typeface = INTEGER(vfont)[0];
1420
	fontindex = INTEGER(vfont)[1];
1420
	fontindex = INTEGER(vfont)[1];
1421
    }
1421
    }
1422
    args = CDR(args);
1422
    args = CDR(args);
1423
 
1423
 
1424
    rawcol = CAR(args);
1424
    rawcol = CAR(args);
1425
    PROTECT(col = FixupCol(rawcol, R_TRANWHITE));
1425
    PROTECT(col = FixupCol(rawcol, R_TRANWHITE));
1426
    ncol = length(col);
1426
    ncol = length(col);
1427
    args = CDR(args);
1427
    args = CDR(args);
1428
 
1428
 
1429
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));
1429
    PROTECT(lty = FixupLty(CAR(args), Rf_gpptr(dd)->lty));
1430
    nlty = length(lty);
1430
    nlty = length(lty);
1431
    args = CDR(args);
1431
    args = CDR(args);
1432
 
1432
 
1433
    PROTECT(lwd = FixupLwd(CAR(args), Rf_gpptr(dd)->lwd));
1433
    PROTECT(lwd = FixupLwd(CAR(args), Rf_gpptr(dd)->lwd));
1434
    nlwd = length(lwd);
1434
    nlwd = length(lwd);
1435
    args = CDR(args);
1435
    args = CDR(args);
1436
 
1436
 
1437
    if (nx < 2 || ny < 2)
1437
    if (nx < 2 || ny < 2)
1438
	error(_("insufficient 'x' or 'y' values"));
1438
	error(_("insufficient 'x' or 'y' values"));
1439
 
1439
 
1440
    if (nrows(z) != nx || ncols(z) != ny)
1440
    if (nrows(z) != nx || ncols(z) != ny)
1441
	error(_("dimension mismatch"));
1441
	error(_("dimension mismatch"));
1442
 
1442
 
1443
    if (nc < 1)
1443
    if (nc < 1)
1444
	error(_("no contour values"));
1444
	error(_("no contour values"));
1445
 
1445
 
1446
    for (i = 0; i < nx; i++) {
1446
    for (i = 0; i < nx; i++) {
1447
	if (!R_FINITE(REAL(x)[i]))
1447
	if (!R_FINITE(REAL(x)[i]))
1448
	    error(_("missing 'x' values"));
1448
	    error(_("missing 'x' values"));
1449
	if (i > 0 && REAL(x)[i] < REAL(x)[i - 1])
1449
	if (i > 0 && REAL(x)[i] < REAL(x)[i - 1])
1450
	    error(_("increasing 'x' values expected"));
1450
	    error(_("increasing 'x' values expected"));
1451
    }
1451
    }
1452
 
1452
 
1453
    for (i = 0; i < ny; i++) {
1453
    for (i = 0; i < ny; i++) {
1454
	if (!R_FINITE(REAL(y)[i]))
1454
	if (!R_FINITE(REAL(y)[i]))
1455
	    error(_("missing 'y' values"));
1455
	    error(_("missing 'y' values"));
1456
	if (i > 0 && REAL(y)[i] < REAL(y)[i - 1])
1456
	if (i > 0 && REAL(y)[i] < REAL(y)[i - 1])
1457
	    error(_("increasing 'y' values expected"));
1457
	    error(_("increasing 'y' values expected"));
1458
    }
1458
    }
1459
 
1459
 
1460
    for (i = 0; i < nc; i++)
1460
    for (i = 0; i < nc; i++)
1461
	if (!R_FINITE(REAL(c)[i]))
1461
	if (!R_FINITE(REAL(c)[i]))
1462
	    error(_("invalid NA contour values"));
1462
	    error(_("invalid NA contour values"));
1463
 
1463
 
1464
    zmin = DBL_MAX;
1464
    zmin = DBL_MAX;
1465
    zmax = DBL_MIN;
1465
    zmax = DBL_MIN;
1466
    for (i = 0; i < nx * ny; i++)
1466
    for (i = 0; i < nx * ny; i++)
1467
	if (R_FINITE(REAL(z)[i])) {
1467
	if (R_FINITE(REAL(z)[i])) {
1468
	    if (zmax < REAL(z)[i]) zmax =  REAL(z)[i];
1468
	    if (zmax < REAL(z)[i]) zmax =  REAL(z)[i];
1469
	    if (zmin > REAL(z)[i]) zmin =  REAL(z)[i];
1469
	    if (zmin > REAL(z)[i]) zmin =  REAL(z)[i];
1470
	}
1470
	}
1471
 
1471
 
1472
    if (zmin >= zmax) {
1472
    if (zmin >= zmax) {
1473
	if (zmin == zmax)
1473
	if (zmin == zmax)
1474
	    warning(_("all z values are equal"));
1474
	    warning(_("all z values are equal"));
1475
	else
1475
	else
1476
	    warning(_("all z values are NA"));
1476
	    warning(_("all z values are NA"));
1477
        UNPROTECT(4);
1477
        UNPROTECT(4);
1478
	return R_NilValue;
1478
	return R_NilValue;
1479
    }
1479
    }
1480
 
1480
 
1481
    /* change to 1e-3, reconsidered because of PR#897
1481
    /* change to 1e-3, reconsidered because of PR#897
1482
     * but 1e-7, and even  2*DBL_EPSILON do not prevent inf.loop in contour().
1482
     * but 1e-7, and even  2*DBL_EPSILON do not prevent inf.loop in contour().
1483
     * maybe something like   16 * DBL_EPSILON * (..).
1483
     * maybe something like   16 * DBL_EPSILON * (..).
1484
     * see also max_contour_segments above */
1484
     * see also max_contour_segments above */
1485
    atom = 1e-3 * (zmax - zmin);
1485
    atom = 1e-3 * (zmax - zmin);
1486
 
1486
 
1487
    /* Initialize the segment data base */
1487
    /* Initialize the segment data base */
1488
 
1488
 
1489
    /* Note we must be careful about resetting */
1489
    /* Note we must be careful about resetting */
1490
    /* the top of the stack, otherwise we run out of */
1490
    /* the top of the stack, otherwise we run out of */
1491
    /* memory after a sequence of displaylist replays */
1491
    /* memory after a sequence of displaylist replays */
1492
 
1492
 
1493
    vmax0 = vmaxget();
1493
    vmax0 = vmaxget();
1494
    ctr_SegDB = (SEGP*)R_alloc(nx*ny, sizeof(SEGP));
1494
    ctr_SegDB = (SEGP*)R_alloc(nx*ny, sizeof(SEGP));
1495
 
1495
 
1496
    for (i = 0; i < nx; i++)
1496
    for (i = 0; i < nx; i++)
1497
	for (j = 0; j < ny; j++)
1497
	for (j = 0; j < ny; j++)
1498
	    ctr_SegDB[i + j * nx] = NULL;
1498
	    ctr_SegDB[i + j * nx] = NULL;
1499
 
1499
 
1500
    /* Draw the contours -- note the heap release */
1500
    /* Draw the contours -- note the heap release */
1501
 
1501
 
1502
    ltysave = Rf_gpptr(dd)->lty;
1502
    ltysave = Rf_gpptr(dd)->lty;
1503
    colsave = Rf_gpptr(dd)->col;
1503
    colsave = Rf_gpptr(dd)->col;
1504
    lwdsave = Rf_gpptr(dd)->lwd;
1504
    lwdsave = Rf_gpptr(dd)->lwd;
1505
    cexsave = Rf_gpptr(dd)->cex;
1505
    cexsave = Rf_gpptr(dd)->cex;
1506
    labelList = PROTECT(R_NilValue);
1506
    labelList = PROTECT(R_NilValue);
1507
 
1507
 
1508
 
1508
 
1509
    /* draw contour for levels[i] */
1509
    /* draw contour for levels[i] */
1510
    GMode(1, dd);
1510
    GMode(1, dd);
1511
    for (i = 0; i < nc; i++) {
1511
    for (i = 0; i < nc; i++) {
1512
	vmax = vmaxget();
1512
	vmax = vmaxget();
1513
	Rf_gpptr(dd)->lty = INTEGER(lty)[i % nlty];
1513
	Rf_gpptr(dd)->lty = INTEGER(lty)[i % nlty];
1514
	if (Rf_gpptr(dd)->lty == NA_INTEGER)
1514
	if (Rf_gpptr(dd)->lty == NA_INTEGER)
1515
	    Rf_gpptr(dd)->lty = ltysave;
1515
	    Rf_gpptr(dd)->lty = ltysave;
1516
	if (isNAcol(rawcol, i, ncol))
1516
	if (isNAcol(rawcol, i, ncol))
1517
	    Rf_gpptr(dd)->col = colsave;
1517
	    Rf_gpptr(dd)->col = colsave;
1518
	else
1518
	else
1519
	    Rf_gpptr(dd)->col = INTEGER(col)[i % ncol];
1519
	    Rf_gpptr(dd)->col = INTEGER(col)[i % ncol];
1520
	Rf_gpptr(dd)->lwd = REAL(lwd)[i % nlwd];
1520
	Rf_gpptr(dd)->lwd = REAL(lwd)[i % nlwd];
1521
	if (!R_FINITE(Rf_gpptr(dd)->lwd))
1521
	if (!R_FINITE(Rf_gpptr(dd)->lwd))
1522
	    Rf_gpptr(dd)->lwd = lwdsave;
1522
	    Rf_gpptr(dd)->lwd = lwdsave;
1523
	Rf_gpptr(dd)->cex = labcex;
1523
	Rf_gpptr(dd)->cex = labcex;
1524
	contour(x, nx, y, ny, z, REAL(c)[i], labels, i,
1524
	contour(x, nx, y, ny, z, REAL(c)[i], labels, i,
1525
		drawLabels, method-1,
1525
		drawLabels, method-1,
1526
		vectorFonts, typeface, fontindex, atom, dd);
1526
		vectorFonts, typeface, fontindex, atom, dd);
1527
	vmaxset(vmax);
1527
	vmaxset(vmax);
1528
    }
1528
    }
1529
    GMode(0, dd);
1529
    GMode(0, dd);
1530
    vmaxset(vmax0);
1530
    vmaxset(vmax0);
1531
    Rf_gpptr(dd)->lty = ltysave;
1531
    Rf_gpptr(dd)->lty = ltysave;
1532
    Rf_gpptr(dd)->col = colsave;
1532
    Rf_gpptr(dd)->col = colsave;
1533
    Rf_gpptr(dd)->lwd = lwdsave;
1533
    Rf_gpptr(dd)->lwd = lwdsave;
1534
    Rf_gpptr(dd)->cex = cexsave;
1534
    Rf_gpptr(dd)->cex = cexsave;
1535
    UNPROTECT(5);
1535
    UNPROTECT(5);
1536
    /* NOTE: only record operation if no "error"  */
1536
    /* NOTE: only record operation if no "error"  */
1537
    /* NOTE: on replay, call == R_NilValue */
1537
    /* NOTE: on replay, call == R_NilValue */
1538
    if (GRecording(call, dd))
1538
    if (GRecording(call, dd))
1539
	recordGraphicOperation(op, oargs, dd);
1539
	recordGraphicOperation(op, oargs, dd);
1540
    return result;
1540
    return result;
1541
}
1541
}
1542
 
1542
 
1543
 
1543
 
1544
	/*  F i l l e d   C o n t o u r   P l o t s  */
1544
	/*  F i l l e d   C o n t o u r   P l o t s  */
1545
 
1545
 
1546
	/*  R o s s  I h a k a,  M a r c h  1 9 9 9  */
1546
	/*  R o s s  I h a k a,  M a r c h  1 9 9 9  */
1547
 
1547
 
1548
static void
1548
static void
1549
FindCutPoints(double low, double high,
1549
FindCutPoints(double low, double high,
1550
	      double x1, double y1, double z1,
1550
	      double x1, double y1, double z1,
1551
	      double x2, double y2, double z2,
1551
	      double x2, double y2, double z2,
1552
	      double *x, double *y, double *z,
1552
	      double *x, double *y, double *z,
1553
	      int *npt)
1553
	      int *npt)
1554
{
1554
{
1555
    double c;
1555
    double c;
1556
 
1556
 
1557
    if (z1 > z2 ) {
1557
    if (z1 > z2 ) {
1558
	if (z2 > high || z1 < low)
1558
	if (z2 > high || z1 < low)
1559
	    return;
1559
	    return;
1560
	if (z1 < high) {
1560
	if (z1 < high) {
1561
	    x[*npt] = x1;
1561
	    x[*npt] = x1;
1562
	    y[*npt] = y1;
1562
	    y[*npt] = y1;
1563
	    z[*npt] = z1;
1563
	    z[*npt] = z1;
1564
	    ++*npt;
1564
	    ++*npt;
1565
	}
1565
	}
1566
	else {
1566
	else {
1567
	    c = (z1 - high) / (z1 - z2);
1567
	    c = (z1 - high) / (z1 - z2);
1568
	    x[*npt] = x1 + c * (x2 - x1);
1568
	    x[*npt] = x1 + c * (x2 - x1);
1569
	    y[*npt] = y1;
1569
	    y[*npt] = y1;
1570
	    z[*npt] = z1 + c * (z2 - z1);
1570
	    z[*npt] = z1 + c * (z2 - z1);
1571
	    ++*npt;
1571
	    ++*npt;
1572
	}
1572
	}
1573
	if (z2 > low) {
1573
	if (z2 > low) {
1574
	}
1574
	}
1575
	else {
1575
	else {
1576
	    c = (z2 -low) / (z2 - z1);
1576
	    c = (z2 -low) / (z2 - z1);
1577
	    x[*npt] = x2 - c * (x2 - x1);
1577
	    x[*npt] = x2 - c * (x2 - x1);
1578
	    y[*npt] = y1;
1578
	    y[*npt] = y1;
1579
	    z[*npt] = z2 - c * (z2 - z1);
1579
	    z[*npt] = z2 - c * (z2 - z1);
1580
	    ++*npt;
1580
	    ++*npt;
1581
	}
1581
	}
1582
    }
1582
    }
1583
    else if (z1 < z2) {
1583
    else if (z1 < z2) {
1584
	if (z2 < low || z1 > high)
1584
	if (z2 < low || z1 > high)
1585
	    return;
1585
	    return;
1586
	if (z1 > low) {
1586
	if (z1 > low) {
1587
	    x[*npt] = x1;
1587
	    x[*npt] = x1;
1588
	    y[*npt] = y1;
1588
	    y[*npt] = y1;
1589
	    z[*npt] = z1;
1589
	    z[*npt] = z1;
1590
	    ++*npt;
1590
	    ++*npt;
1591
	}
1591
	}
1592
	else {
1592
	else {
1593
	    c = (z1 - low) / (z1 - z2);
1593
	    c = (z1 - low) / (z1 - z2);
1594
	    x[*npt] = x1 + c * (x2 - x1);
1594
	    x[*npt] = x1 + c * (x2 - x1);
1595
	    y[*npt] = y1;
1595
	    y[*npt] = y1;
1596
	    z[*npt] = z1 + c * (z2 - z1);
1596
	    z[*npt] = z1 + c * (z2 - z1);
1597
	    ++*npt;
1597
	    ++*npt;
1598
	}
1598
	}
1599
	if (z2 < high) {
1599
	if (z2 < high) {
1600
#ifdef OMIT
1600
#ifdef OMIT
1601
	    /* Don't repeat corner vertices */
1601
	    /* Don't repeat corner vertices */
1602
	    x[*npt] = x2;
1602
	    x[*npt] = x2;
1603
	    y[*npt] = y2;
1603
	    y[*npt] = y2;
1604
	    z[*npt] = z2;
1604
	    z[*npt] = z2;
1605
	    ++*npt;
1605
	    ++*npt;
1606
#endif
1606
#endif
1607
	}
1607
	}
1608
	else {
1608
	else {
1609
	    c = (z2 - high) / (z2 - z1);
1609
	    c = (z2 - high) / (z2 - z1);
1610
	    x[*npt] = x2 - c * (x2 - x1);
1610
	    x[*npt] = x2 - c * (x2 - x1);
1611
	    y[*npt] = y1;
1611
	    y[*npt] = y1;
1612
	    z[*npt] = z2 - c * (z2 - z1);
1612
	    z[*npt] = z2 - c * (z2 - z1);
1613
	    ++*npt;
1613
	    ++*npt;
1614
	}
1614
	}
1615
    }
1615
    }
1616
    else {
1616
    else {
1617
	if(low <= z1 && z1 <= high) {
1617
	if(low <= z1 && z1 <= high) {
1618
	    x[*npt] = x1;
1618
	    x[*npt] = x1;
1619
	    y[*npt] = y1;
1619
	    y[*npt] = y1;
1620
	    z[*npt] = z1;
1620
	    z[*npt] = z1;
1621
	    ++*npt;
1621
	    ++*npt;
1622
#ifdef OMIT
1622
#ifdef OMIT
1623
	    /* Don't repeat corner vertices */
1623
	    /* Don't repeat corner vertices */
1624
	    x[*npt] = x2;
1624
	    x[*npt] = x2;
1625
	    y[*npt] = y2;
1625
	    y[*npt] = y2;
1626
	    z[*npt] = z2;
1626
	    z[*npt] = z2;
1627
	    ++*npt;
1627
	    ++*npt;
1628
#endif
1628
#endif
1629
	}
1629
	}
1630
    }
1630
    }
1631
}
1631
}
1632
 
1632
 
1633
/* FIXME - This could pretty easily be adapted to handle NA */
1633
/* FIXME - This could pretty easily be adapted to handle NA */
1634
/* values on the grid.  Just search the diagonals for cutpoints */
1634
/* values on the grid.  Just search the diagonals for cutpoints */
1635
/* instead of the cell sides.  Use the same switch idea as in */
1635
/* instead of the cell sides.  Use the same switch idea as in */
1636
/* contour above.  There are 5 cases to handle. */
1636
/* contour above.  There are 5 cases to handle. */
1637
 
1637
 
1638
static void
1638
static void
1639
FindPolygonVertices(double low, double high,
1639
FindPolygonVertices(double low, double high,
1640
		    double x1, double x2, double y1, double y2,
1640
		    double x1, double x2, double y1, double y2,
1641
		    double z11, double z21, double z12, double z22,
1641
		    double z11, double z21, double z12, double z22,
1642
		    double *x, double *y, double *z, int *npt)
1642
		    double *x, double *y, double *z, int *npt)
1643
{
1643
{
1644
    *npt = 0;
1644
    *npt = 0;
1645
    FindCutPoints(low, high, x1,  y1,  z11, x2,  y1,  z21, x, y, z, npt);
1645
    FindCutPoints(low, high, x1,  y1,  z11, x2,  y1,  z21, x, y, z, npt);
1646
    FindCutPoints(low, high, y1,  x2,  z21, y2,  x2,  z22, y, x, z, npt);
1646
    FindCutPoints(low, high, y1,  x2,  z21, y2,  x2,  z22, y, x, z, npt);
1647
    FindCutPoints(low, high, x2,  y2,  z22, x1,  y2,  z12, x, y, z, npt);
1647
    FindCutPoints(low, high, x2,  y2,  z22, x1,  y2,  z12, x, y, z, npt);
1648
    FindCutPoints(low, high, y2,  x1,  z12, y1,  x1,  z11, y, x, z, npt);
1648
    FindCutPoints(low, high, y2,  x1,  z12, y1,  x1,  z11, y, x, z, npt);
1649
}
1649
}
1650
 
1650
 
1651
/* FIXME: [Code consistency] Use macro for the parallel parts of
1651
/* FIXME: [Code consistency] Use macro for the parallel parts of
1652
	  do_contour, do_filledcontour & do_image ...
1652
	  do_contour, do_filledcontour & do_image ...
1653
*/
1653
*/
1654
 
1654
 
1655
/* filledcontour(x, y, z, levels, col) */
1655
/* filledcontour(x, y, z, levels, col) */
1656
SEXP attribute_hidden do_filledcontour(SEXP call, SEXP op, SEXP args, SEXP env)
1656
SEXP attribute_hidden do_filledcontour(SEXP call, SEXP op, SEXP args, SEXP env)
1657
{
1657
{
1658
    SEXP oargs, sx, sy, sz, sc, scol;
1658
    SEXP oargs, sx, sy, sz, sc, scol;
1659
    double *x, *y, *z, *c;
1659
    double *x, *y, *z, *c;
1660
    unsigned *col;
1660
    unsigned *col;
1661
    int i, j, k, npt, nx, ny, nz, nc, ncol, colsave, xpdsave;
1661
    int i, j, k, npt, nx, ny, nz, nc, ncol, colsave, xpdsave;
1662
    double px[8], py[8], pz[8];
1662
    double px[8], py[8], pz[8];
1663
    DevDesc *dd = CurrentDevice();
1663
    DevDesc *dd = CurrentDevice();
1664
 
1664
 
1665
    GCheckState(dd);
1665
    GCheckState(dd);
1666
 
1666
 
1667
    checkArity(op,args);
1667
    checkArity(op,args);
1668
    oargs = args;
1668
    oargs = args;
1669
 
1669
 
1670
    sx = CAR(args);
1670
    sx = CAR(args);
1671
    internalTypeCheck(call, sx, REALSXP);
1671
    internalTypeCheck(call, sx, REALSXP);
1672
    nx = LENGTH(sx);
1672
    nx = LENGTH(sx);
1673
    args = CDR(args);
1673
    args = CDR(args);
1674
 
1674
 
1675
    sy = CAR(args);
1675
    sy = CAR(args);
1676
    internalTypeCheck(call, sy, REALSXP);
1676
    internalTypeCheck(call, sy, REALSXP);
1677
    ny = LENGTH(sy);
1677
    ny = LENGTH(sy);
1678
    args = CDR(args);
1678
    args = CDR(args);
1679
 
1679
 
1680
    sz = CAR(args);
1680
    sz = CAR(args);
1681
    internalTypeCheck(call, sz, REALSXP);
1681
    internalTypeCheck(call, sz, REALSXP);
1682
    nz = length(sz);
1682
    nz = length(sz);
1683
    args = CDR(args);
1683
    args = CDR(args);
1684
 
1684
 
1685
    sc = CAR(args);/* levels */
1685
    sc = CAR(args);/* levels */
1686
    internalTypeCheck(call, sc, REALSXP);
1686
    internalTypeCheck(call, sc, REALSXP);
1687
    nc = length(sc);
1687
    nc = length(sc);
1688
    args = CDR(args);
1688
    args = CDR(args);
1689
 
1689
 
1690
    if (nx < 2 || ny < 2)
1690
    if (nx < 2 || ny < 2)
1691
	error(_("insufficient 'x' or 'y' values"));
1691
	error(_("insufficient 'x' or 'y' values"));
1692
 
1692
 
1693
    if (nrows(sz) != nx || ncols(sz) != ny)
1693
    if (nrows(sz) != nx || ncols(sz) != ny)
1694
	error(_("dimension mismatch"));
1694
	error(_("dimension mismatch"));
1695
 
1695
 
1696
    if (nc < 1)
1696
    if (nc < 1)
1697
	error(_("no contour values"));
1697
	error(_("no contour values"));
1698
 
1698
 
1699
    PROTECT(scol = FixupCol(CAR(args), R_TRANWHITE));
1699
    PROTECT(scol = FixupCol(CAR(args), R_TRANWHITE));
1700
    ncol = length(scol);
1700
    ncol = length(scol);
1701
 
1701
 
1702
    /* Shorthand Pointers */
1702
    /* Shorthand Pointers */
1703
 
1703
 
1704
    x = REAL(sx);
1704
    x = REAL(sx);
1705
    y = REAL(sy);
1705
    y = REAL(sy);
1706
    z = REAL(sz);
1706
    z = REAL(sz);
1707
    c = REAL(sc);
1707
    c = REAL(sc);
1708
    col = (unsigned*)INTEGER(scol);
1708
    col = (unsigned*)INTEGER(scol);
1709
 
1709
 
1710
    /* Check of grid coordinates */
1710
    /* Check of grid coordinates */
1711
    /* We want them to all be finite */
1711
    /* We want them to all be finite */
1712
    /* and in strictly ascending order */
1712
    /* and in strictly ascending order */
1713
 
1713
 
1714
    if (nx < 1 || ny < 1) goto badxy;
1714
    if (nx < 1 || ny < 1) goto badxy;
1715
    if (!R_FINITE(x[0])) goto badxy;
1715
    if (!R_FINITE(x[0])) goto badxy;
1716
    if (!R_FINITE(y[0])) goto badxy;
1716
    if (!R_FINITE(y[0])) goto badxy;
1717
    for (i = 1; i < nx; i++)
1717
    for (i = 1; i < nx; i++)
1718
	if (!R_FINITE(x[i]) || x[i] <= x[i - 1]) goto badxy;
1718
	if (!R_FINITE(x[i]) || x[i] <= x[i - 1]) goto badxy;
1719
    for (j = 1; j < ny; j++)
1719
    for (j = 1; j < ny; j++)
1720
	if (!R_FINITE(y[j]) || y[j] <= y[j - 1]) goto badxy;
1720
	if (!R_FINITE(y[j]) || y[j] <= y[j - 1]) goto badxy;
1721
 
1721
 
1722
    /* Check of the contour levels */
1722
    /* Check of the contour levels */
1723
 
1723
 
1724
    if (!R_FINITE(c[0])) goto badlev;
1724
    if (!R_FINITE(c[0])) goto badlev;
1725
    for (k = 1; k < nc; k++)
1725
    for (k = 1; k < nc; k++)
1726
	if (!R_FINITE(c[k]) || c[k] <= c[k - 1]) goto badlev;
1726
	if (!R_FINITE(c[k]) || c[k] <= c[k - 1]) goto badlev;
1727
 
1727
 
1728
    colsave = Rf_gpptr(dd)->col;
1728
    colsave = Rf_gpptr(dd)->col;
1729
    xpdsave = Rf_gpptr(dd)->xpd;
1729
    xpdsave = Rf_gpptr(dd)->xpd;
1730
    /* override par("xpd") and force clipping to plot region */
1730
    /* override par("xpd") and force clipping to plot region */
1731
    Rf_gpptr(dd)->xpd = 0;
1731
    Rf_gpptr(dd)->xpd = 0;
1732
 
1732
 
1733
    GMode(1, dd);
1733
    GMode(1, dd);
1734
 
1734
 
1735
    for (i = 1; i < nx; i++) {
1735
    for (i = 1; i < nx; i++) {
1736
	for (j = 1; j < ny; j++) {
1736
	for (j = 1; j < ny; j++) {
1737
	    for (k = 1; k < nc ; k++) {
1737
	    for (k = 1; k < nc ; k++) {
1738
		FindPolygonVertices(c[k - 1], c[k],
1738
		FindPolygonVertices(c[k - 1], c[k],
1739
				    x[i - 1], x[i],
1739
				    x[i - 1], x[i],
1740
				    y[j - 1], y[j],
1740
				    y[j - 1], y[j],
1741
				    z[i - 1 + (j - 1) * nx],
1741
				    z[i - 1 + (j - 1) * nx],
1742
				    z[i + (j - 1) * nx],
1742
				    z[i + (j - 1) * nx],
1743
				    z[i - 1 + j * nx],
1743
				    z[i - 1 + j * nx],
1744
				    z[i + j * nx],
1744
				    z[i + j * nx],
1745
				    px, py, pz, &npt);
1745
				    px, py, pz, &npt);
1746
                if (npt > 2)
1746
                if (npt > 2)
1747
		    GPolygon(npt, px, py, USER, col[(k-1)%ncol],
1747
		    GPolygon(npt, px, py, USER, col[(k-1)%ncol],
1748
			     R_TRANWHITE, dd);
1748
			     R_TRANWHITE, dd);
1749
	    }
1749
	    }
1750
	}
1750
	}
1751
    }
1751
    }
1752
    GMode(0, dd);
1752
    GMode(0, dd);
1753
    Rf_gpptr(dd)->col = colsave;
1753
    Rf_gpptr(dd)->col = colsave;
1754
    Rf_gpptr(dd)->xpd = xpdsave;
1754
    Rf_gpptr(dd)->xpd = xpdsave;
1755
    UNPROTECT(1);
1755
    UNPROTECT(1);
1756
    if (GRecording(call, dd))
1756
    if (GRecording(call, dd))
1757
	recordGraphicOperation(op, oargs, dd);
1757
	recordGraphicOperation(op, oargs, dd);
1758
    return R_NilValue;
1758
    return R_NilValue;
1759
 
1759
 
1760
 badxy:
1760
 badxy:
1761
    error(_("invalid x / y values or limits"));
1761
    error(_("invalid x / y values or limits"));
1762
 badlev:
1762
 badlev:
1763
    error(_("invalid contour levels: must be strictly increasing"));
1763
    error(_("invalid contour levels: must be strictly increasing"));
1764
    return R_NilValue;  /* never used; to keep -Wall happy */
1764
    return R_NilValue;  /* never used; to keep -Wall happy */
1765
}
1765
}
1766
 
1766
 
1767
 
1767
 
1768
	/*  I m a g e   R e n d e r i n g  */
1768
	/*  I m a g e   R e n d e r i n g  */
1769
 
1769
 
1770
 
1770
 
1771
/* image(x, y, z, col, breaks) */
1771
/* image(x, y, z, col, breaks) */
1772
SEXP attribute_hidden do_image(SEXP call, SEXP op, SEXP args, SEXP env)
1772
SEXP attribute_hidden do_image(SEXP call, SEXP op, SEXP args, SEXP env)
1773
{
1773
{
1774
    SEXP oargs, sx, sy, sz, sc;
1774
    SEXP oargs, sx, sy, sz, sc;
1775
    double *x, *y;
1775
    double *x, *y;
1776
    int *z, tmp;
1776
    int *z, tmp;
1777
    unsigned *c;
1777
    unsigned *c;
1778
    int i, j, nx, ny, nc, colsave, xpdsave;
1778
    int i, j, nx, ny, nc, colsave, xpdsave;
1779
    DevDesc *dd = CurrentDevice();
1779
    DevDesc *dd = CurrentDevice();
1780
 
1780
 
1781
    GCheckState(dd);
1781
    GCheckState(dd);
1782
 
1782
 
1783
    checkArity(op,args);
1783
    checkArity(op,args);
1784
    oargs = args;
1784
    oargs = args;
1785
 
1785
 
1786
    sx = CAR(args);
1786
    sx = CAR(args);
1787
    internalTypeCheck(call, sx, REALSXP);
1787
    internalTypeCheck(call, sx, REALSXP);
1788
    nx = LENGTH(sx);
1788
    nx = LENGTH(sx);
1789
    args = CDR(args);
1789
    args = CDR(args);
1790
 
1790
 
1791
    sy = CAR(args);
1791
    sy = CAR(args);
1792
    internalTypeCheck(call, sy, REALSXP);
1792
    internalTypeCheck(call, sy, REALSXP);
1793
    ny = LENGTH(sy);
1793
    ny = LENGTH(sy);
1794
    args = CDR(args);
1794
    args = CDR(args);
1795
 
1795
 
1796
    sz = CAR(args);
1796
    sz = CAR(args);
1797
    internalTypeCheck(call, sz, INTSXP);
1797
    internalTypeCheck(call, sz, INTSXP);
1798
    args = CDR(args);
1798
    args = CDR(args);
1799
 
1799
 
1800
    PROTECT(sc = FixupCol(CAR(args), R_TRANWHITE));
1800
    PROTECT(sc = FixupCol(CAR(args), R_TRANWHITE));
1801
    nc = LENGTH(sc);
1801
    nc = LENGTH(sc);
1802
 
1802
 
1803
    /* Shorthand Pointers */
1803
    /* Shorthand Pointers */
1804
 
1804
 
1805
    x = REAL(sx);
1805
    x = REAL(sx);
1806
    y = REAL(sy);
1806
    y = REAL(sy);
1807
    z = INTEGER(sz);
1807
    z = INTEGER(sz);
1808
    c = (unsigned*)INTEGER(sc);
1808
    c = (unsigned*)INTEGER(sc);
1809
 
1809
 
1810
    /* Check of grid coordinates now done in C code */
1810
    /* Check of grid coordinates now done in C code */
1811
 
1811
 
1812
    colsave = Rf_gpptr(dd)->col;
1812
    colsave = Rf_gpptr(dd)->col;
1813
    xpdsave = Rf_gpptr(dd)->xpd;
1813
    xpdsave = Rf_gpptr(dd)->xpd;
1814
    /* override par("xpd") and force clipping to plot region */
1814
    /* override par("xpd") and force clipping to plot region */
1815
    Rf_gpptr(dd)->xpd = 0;
1815
    Rf_gpptr(dd)->xpd = 0;
1816
 
1816
 
1817
    GMode(1, dd);
1817
    GMode(1, dd);
1818
 
1818
 
1819
    for (i = 0; i < nx - 1 ; i++) {
1819
    for (i = 0; i < nx - 1 ; i++) {
1820
	for (j = 0; j < ny - 1; j++) {
1820
	for (j = 0; j < ny - 1; j++) {
1821
	    tmp = z[i + j * (nx - 1)];
1821
	    tmp = z[i + j * (nx - 1)];
1822
	    if (tmp >= 0 && tmp < nc && tmp != NA_INTEGER)
1822
	    if (tmp >= 0 && tmp < nc && tmp != NA_INTEGER)
1823
		GRect(x[i], y[j], x[i+1], y[j+1], USER, c[tmp],
1823
		GRect(x[i], y[j], x[i+1], y[j+1], USER, c[tmp],
1824
		      R_TRANWHITE, dd);
1824
		      R_TRANWHITE, dd);
1825
	}
1825
	}
1826
    }
1826
    }
1827
    GMode(0, dd);
1827
    GMode(0, dd);
1828
    Rf_gpptr(dd)->col = colsave;
1828
    Rf_gpptr(dd)->col = colsave;
1829
    Rf_gpptr(dd)->xpd = xpdsave;
1829
    Rf_gpptr(dd)->xpd = xpdsave;
1830
    UNPROTECT(1);
1830
    UNPROTECT(1);
1831
    if (GRecording(call, dd))
1831
    if (GRecording(call, dd))
1832
	recordGraphicOperation(op, oargs, dd);
1832
	recordGraphicOperation(op, oargs, dd);
1833
    return R_NilValue;
1833
    return R_NilValue;
1834
}
1834
}
1835
 
1835
 
1836
	/*  P e r s p e c t i v e   S u r f a c e   P l o t s  */
1836
	/*  P e r s p e c t i v e   S u r f a c e   P l o t s  */
1837
 
1837
 
1838
 
1838
 
1839
/* Set up the light source */
1839
/* Set up the light source */
1840
static double Light[4];
1840
static double Light[4];
1841
static double Shade;
1841
static double Shade;
1842
static Rboolean DoLighting;
1842
static Rboolean DoLighting;
1843
 
1843
 
1844
static void SetUpLight(double theta, double phi)
1844
static void SetUpLight(double theta, double phi)
1845
{
1845
{
1846
    double u[4];
1846
    double u[4];
1847
    u[0] = 0; u[1] = -1; u[2] = 0; u[3] = 1;
1847
    u[0] = 0; u[1] = -1; u[2] = 0; u[3] = 1;
1848
    SetToIdentity(VT);             /* Initialization */
1848
    SetToIdentity(VT);             /* Initialization */
1849
    XRotate(-phi);                 /* colatitude rotation */
1849
    XRotate(-phi);                 /* colatitude rotation */
1850
    ZRotate(theta);                /* azimuthal rotation */
1850
    ZRotate(theta);                /* azimuthal rotation */
1851
    TransVector(u, VT, Light);	   /* transform */
1851
    TransVector(u, VT, Light);	   /* transform */
1852
}
1852
}
1853
 
1853
 
1854
static double FacetShade(double *u, double *v)
1854
static double FacetShade(double *u, double *v)
1855
{
1855
{
1856
    double nx, ny, nz, sum;
1856
    double nx, ny, nz, sum;
1857
    nx = u[1] * v[2] - u[2] * v[1];
1857
    nx = u[1] * v[2] - u[2] * v[1];
1858
    ny = u[2] * v[0] - u[0] * v[2];
1858
    ny = u[2] * v[0] - u[0] * v[2];
1859
    nz = u[0] * v[1] - u[1] * v[0];
1859
    nz = u[0] * v[1] - u[1] * v[0];
1860
    sum = sqrt(nx * nx + ny * ny + nz * nz);
1860
    sum = sqrt(nx * nx + ny * ny + nz * nz);
1861
    if (sum == 0) sum = 1;
1861
    if (sum == 0) sum = 1;
1862
    nx /= sum;
1862
    nx /= sum;
1863
    ny /= sum;
1863
    ny /= sum;
1864
    nz /= sum;
1864
    nz /= sum;
1865
    sum = 0.5 * (nx * Light[0] + ny * Light[1] + nz * Light[2] + 1);
1865
    sum = 0.5 * (nx * Light[0] + ny * Light[1] + nz * Light[2] + 1);
1866
    return pow(sum, Shade);
1866
    return pow(sum, Shade);
1867
}
1867
}
1868
 
1868
 
1869
 
1869
 
1870
/* For each facet, determine the farthest point from the eye. */
1870
/* For each facet, determine the farthest point from the eye. */
1871
/* Sorting the facets so that these depths are decreasing */
1871
/* Sorting the facets so that these depths are decreasing */
1872
/* yields an occlusion compatible ordering. */
1872
/* yields an occlusion compatible ordering. */
1873
/* Note that we ignore z values when doing this. */
1873
/* Note that we ignore z values when doing this. */
1874
 
1874
 
1875
static void DepthOrder(double *z, double *x, double *y, int nx, int ny,
1875
static void DepthOrder(double *z, double *x, double *y, int nx, int ny,
1876
		       double *depth, int *indx)
1876
		       double *depth, int *indx)
1877
{
1877
{
1878
    int i, ii, j, jj, nx1, ny1;
1878
    int i, ii, j, jj, nx1, ny1;
1879
    Vector3d u, v;
1879
    Vector3d u, v;
1880
    double d;
1880
    double d;
1881
    nx1 = nx - 1;
1881
    nx1 = nx - 1;
1882
    ny1 = ny - 1;
1882
    ny1 = ny - 1;
1883
    for (i = 0; i < nx1 * ny1; i++)
1883
    for (i = 0; i < nx1 * ny1; i++)
1884
	indx[i] = i;
1884
	indx[i] = i;
1885
    for (i = 0; i < nx1; i++)
1885
    for (i = 0; i < nx1; i++)
1886
	for (j = 0; j < ny1; j++) {
1886
	for (j = 0; j < ny1; j++) {
1887
	    d = -DBL_MAX;
1887
	    d = -DBL_MAX;
1888
	    for (ii = 0; ii <= 1; ii++)
1888
	    for (ii = 0; ii <= 1; ii++)
1889
		for (jj = 0; jj <= 1; jj++) {
1889
		for (jj = 0; jj <= 1; jj++) {
1890
		    u[0] = x[i + ii];
1890
		    u[0] = x[i + ii];
1891
		    u[1] = y[j + jj];
1891
		    u[1] = y[j + jj];
1892
		    /* Originally I had the following line here: */
1892
		    /* Originally I had the following line here: */
1893
		    /* u[2] = z[i+ii+(j+jj)*nx]; */
1893
		    /* u[2] = z[i+ii+(j+jj)*nx]; */
1894
		    /* But this leads to artifacts. */
1894
		    /* But this leads to artifacts. */
1895
		    /* It has been replaced by the following line: */
1895
		    /* It has been replaced by the following line: */
1896
		    u[2] = 0;
1896
		    u[2] = 0;
1897
		    u[3] = 1;
1897
		    u[3] = 1;
1898
		    if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
1898
		    if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
1899
			TransVector(u, VT, v);
1899
			TransVector(u, VT, v);
1900
			if (v[3] > d) d = v[3];
1900
			if (v[3] > d) d = v[3];
1901
		    }
1901
		    }
1902
		}
1902
		}
1903
	    depth[i+j*nx1] = -d;
1903
	    depth[i+j*nx1] = -d;
1904
 
1904
 
1905
	}
1905
	}
1906
    /* Determine the depth ordering of the facets to ensure
1906
    /* Determine the depth ordering of the facets to ensure
1907
       that they are drawn in an occlusion compatible order. */
1907
       that they are drawn in an occlusion compatible order. */
1908
    rsort_with_index(depth, indx, nx1 * ny1);
1908
    rsort_with_index(depth, indx, nx1 * ny1);
1909
}
1909
}
1910
 
1910
 
1911
 
1911
 
1912
static void DrawFacets(double *z, double *x, double *y, int nx, int ny,
1912
static void DrawFacets(double *z, double *x, double *y, int nx, int ny,
1913
		       int *indx, double xs, double ys, double zs,
1913
		       int *indx, double xs, double ys, double zs,
1914
	               int *col, int ncol, int border)
1914
	               int *col, int ncol, int border)
1915
{
1915
{
1916
    double xx[4], yy[4], shade = 0;
1916
    double xx[4], yy[4], shade = 0;
1917
    Vector3d u, v;
1917
    Vector3d u, v;
1918
    int i, j, k, n, nx1, ny1, icol, nv;
1918
    int i, j, k, n, nx1, ny1, icol, nv;
1919
    unsigned int newcol, r, g, b;
1919
    unsigned int newcol, r, g, b;
1920
    DevDesc *dd;
1920
    DevDesc *dd;
1921
    dd = CurrentDevice();
1921
    dd = CurrentDevice();
1922
    nx1 = nx - 1;
1922
    nx1 = nx - 1;
1923
    ny1 = ny - 1;
1923
    ny1 = ny - 1;
1924
    n = nx1 * ny1;
1924
    n = nx1 * ny1;
1925
    for (k = 0; k < n; k++) {
1925
    for (k = 0; k < n; k++) {
1926
	nv = 0;
1926
	nv = 0;
1927
	i = indx[k] % nx1;
1927
	i = indx[k] % nx1;
1928
	j = indx[k] / nx1;
1928
	j = indx[k] / nx1;
1929
	icol = (i + j * nx1) % ncol;
1929
	icol = (i + j * nx1) % ncol;
1930
	if (DoLighting) {
1930
	if (DoLighting) {
1931
            /* Note we must scale here */
1931
            /* Note we must scale here */
1932
	    u[0] = xs * (x[i+1] - x[i]);
1932
	    u[0] = xs * (x[i+1] - x[i]);
1933
	    u[1] = ys * (y[j] - y[j+1]);
1933
	    u[1] = ys * (y[j] - y[j+1]);
1934
	    u[2] = zs * (z[(i+1)+j*nx] - z[i+(j+1)*nx]);
1934
	    u[2] = zs * (z[(i+1)+j*nx] - z[i+(j+1)*nx]);
1935
	    v[0] = xs * (x[i+1] - x[i]);
1935
	    v[0] = xs * (x[i+1] - x[i]);
1936
	    v[1] = ys * (y[j+1] - y[j]);
1936
	    v[1] = ys * (y[j+1] - y[j]);
1937
	    v[2] = zs * (z[(i+1)+(j+1)*nx] - z[i+j*nx]);
1937
	    v[2] = zs * (z[(i+1)+(j+1)*nx] - z[i+j*nx]);
1938
	    shade = FacetShade(u, v);
1938
	    shade = FacetShade(u, v);
1939
	}
1939
	}
1940
	u[0] = x[i]; u[1] = y[j];
1940
	u[0] = x[i]; u[1] = y[j];
1941
	u[2] = z[i + j * nx]; u[3] = 1;
1941
	u[2] = z[i + j * nx]; u[3] = 1;
1942
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
1942
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
1943
	    TransVector(u, VT, v);
1943
	    TransVector(u, VT, v);
1944
	    xx[nv] = v[0] / v[3];
1944
	    xx[nv] = v[0] / v[3];
1945
	    yy[nv] = v[1] / v[3];
1945
	    yy[nv] = v[1] / v[3];
1946
	    nv++;
1946
	    nv++;
1947
	}
1947
	}
1948
 
1948
 
1949
	u[0] = x[i + 1]; u[1] = y[j];
1949
	u[0] = x[i + 1]; u[1] = y[j];
1950
	u[2] = z[i + 1 + j * nx]; u[3] = 1;
1950
	u[2] = z[i + 1 + j * nx]; u[3] = 1;
1951
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
1951
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
1952
	    TransVector(u, VT, v);
1952
	    TransVector(u, VT, v);
1953
	    xx[nv] = v[0] / v[3];
1953
	    xx[nv] = v[0] / v[3];
1954
	    yy[nv] = v[1] / v[3];
1954
	    yy[nv] = v[1] / v[3];
1955
	    nv++;
1955
	    nv++;
1956
	}
1956
	}
1957
 
1957
 
1958
	u[0] = x[i + 1]; u[1] = y[j + 1];
1958
	u[0] = x[i + 1]; u[1] = y[j + 1];
1959
	u[2] = z[i + 1 + (j + 1) * nx]; u[3] = 1;
1959
	u[2] = z[i + 1 + (j + 1) * nx]; u[3] = 1;
1960
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
1960
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
1961
	    TransVector(u, VT, v);
1961
	    TransVector(u, VT, v);
1962
	    xx[nv] = v[0] / v[3];
1962
	    xx[nv] = v[0] / v[3];
1963
	    yy[nv] = v[1] / v[3];
1963
	    yy[nv] = v[1] / v[3];
1964
	    nv++;
1964
	    nv++;
1965
	}
1965
	}
1966
 
1966
 
1967
	u[0] = x[i]; u[1] = y[j + 1];
1967
	u[0] = x[i]; u[1] = y[j + 1];
1968
	u[2] = z[i + (j + 1) * nx]; u[3] = 1;
1968
	u[2] = z[i + (j + 1) * nx]; u[3] = 1;
1969
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
1969
	if (R_FINITE(u[0]) &&  R_FINITE(u[1]) && R_FINITE(u[2])) {
1970
	    TransVector(u, VT, v);
1970
	    TransVector(u, VT, v);
1971
	    xx[nv] = v[0] / v[3];
1971
	    xx[nv] = v[0] / v[3];
1972
	    yy[nv] = v[1] / v[3];
1972
	    yy[nv] = v[1] / v[3];
1973
	    nv++;
1973
	    nv++;
1974
	}
1974
	}
1975
 
1975
 
1976
	if (nv > 2) {
1976
	if (nv > 2) {
1977
	    newcol = col[icol];
1977
	    newcol = col[icol];
1978
	    if (DoLighting) {
1978
	    if (DoLighting) {
1979
		r = shade * R_RED(newcol);
1979
		r = shade * R_RED(newcol);
1980
		g = shade * R_GREEN(newcol);
1980
		g = shade * R_GREEN(newcol);
1981
		b = shade * R_BLUE(newcol);
1981
		b = shade * R_BLUE(newcol);
1982
		newcol = R_RGB(r, g, b);
1982
		newcol = R_RGB(r, g, b);
1983
	    }
1983
	    }
1984
	    GPolygon(nv, xx, yy, USER, newcol, border, dd);
1984
	    GPolygon(nv, xx, yy, USER, newcol, border, dd);
1985
	}
1985
	}
1986
    }
1986
    }
1987
}
1987
}
1988
 
1988
 
1989
 
1989
 
1990
#ifdef NOT_used_currently/*-- out 'def'  (-Wall) --*/
1990
#ifdef NOT_used_currently/*-- out 'def'  (-Wall) --*/
1991
static void CheckRange(double *x, int n, double min, double max)
1991
static void CheckRange(double *x, int n, double min, double max)
1992
{
1992
{
1993
    double xmin, xmax;
1993
    double xmin, xmax;
1994
    int i;
1994
    int i;
1995
    xmin =  DBL_MAX;
1995
    xmin =  DBL_MAX;
1996
    xmax = -DBL_MAX;
1996
    xmax = -DBL_MAX;
1997
    for (i = 0; i < n; i++)
1997
    for (i = 0; i < n; i++)
1998
	if (R_FINITE(x[i])) {
1998
	if (R_FINITE(x[i])) {
1999
	    if (x[i] < xmin) xmin = x[i];
1999
	    if (x[i] < xmin) xmin = x[i];
2000
	    if (x[i] > xmax) xmax = x[i];
2000
	    if (x[i] > xmax) xmax = x[i];
2001
	}
2001
	}
2002
    if (xmin < min || xmax > max)
2002
    if (xmin < min || xmax > max)
2003
	errorcall(gcall, _("coordinates outsize specified range"));
2003
	errorcall(gcall, _("coordinates outsize specified range"));
2004
}
2004
}
2005
#endif
2005
#endif
2006
 
2006
 
2007
static void PerspWindow(double *xlim, double *ylim, double *zlim, DevDesc *dd)
2007
static void PerspWindow(double *xlim, double *ylim, double *zlim, DevDesc *dd)
2008
{
2008
{
2009
    double pin1, pin2, scale, xdelta, ydelta, xscale, yscale, xadd, yadd;
2009
    double pin1, pin2, scale, xdelta, ydelta, xscale, yscale, xadd, yadd;
2010
    double xmax, xmin, ymax, ymin, xx, yy;
2010
    double xmax, xmin, ymax, ymin, xx, yy;
2011
    Vector3d u, v;
2011
    Vector3d u, v;
2012
    int i, j, k;
2012
    int i, j, k;
2013
 
2013
 
2014
    xmax = xmin = ymax = ymin = 0;
2014
    xmax = xmin = ymax = ymin = 0;
2015
    u[3] = 1;
2015
    u[3] = 1;
2016
    for (i = 0; i < 2; i++) {
2016
    for (i = 0; i < 2; i++) {
2017
	u[0] = xlim[i];
2017
	u[0] = xlim[i];
2018
	for (j = 0; j < 2; j++) {
2018
	for (j = 0; j < 2; j++) {
2019
	    u[1] = ylim[j];
2019
	    u[1] = ylim[j];
2020
	    for (k = 0; k < 2; k++) {
2020
	    for (k = 0; k < 2; k++) {
2021
		u[2] = zlim[k];
2021
		u[2] = zlim[k];
2022
		TransVector(u, VT, v);
2022
		TransVector(u, VT, v);
2023
		xx = v[0] / v[3];
2023
		xx = v[0] / v[3];
2024
		yy = v[1] / v[3];
2024
		yy = v[1] / v[3];
2025
		if (xx > xmax) xmax = xx;
2025
		if (xx > xmax) xmax = xx;
2026
		if (xx < xmin) xmin = xx;
2026
		if (xx < xmin) xmin = xx;
2027
		if (yy > ymax) ymax = yy;
2027
		if (yy > ymax) ymax = yy;
2028
		if (yy < ymin) ymin = yy;
2028
		if (yy < ymin) ymin = yy;
2029
	    }
2029
	    }
2030
	}
2030
	}
2031
    }
2031
    }
2032
    pin1 = GConvertXUnits(1.0, NPC, INCHES, dd);
2032
    pin1 = GConvertXUnits(1.0, NPC, INCHES, dd);
2033
    pin2 = GConvertYUnits(1.0, NPC, INCHES, dd);
2033
    pin2 = GConvertYUnits(1.0, NPC, INCHES, dd);
2034
    xdelta = fabs(xmax - xmin);
2034
    xdelta = fabs(xmax - xmin);
2035
    ydelta = fabs(ymax - ymin);
2035
    ydelta = fabs(ymax - ymin);
2036
    xscale = pin1 / xdelta;
2036
    xscale = pin1 / xdelta;
2037
    yscale = pin2 / ydelta;
2037
    yscale = pin2 / ydelta;
2038
    scale = (xscale < yscale) ? xscale : yscale;
2038
    scale = (xscale < yscale) ? xscale : yscale;
2039
    xadd = .5 * (pin1 / scale - xdelta);
2039
    xadd = .5 * (pin1 / scale - xdelta);
2040
    yadd = .5 * (pin2 / scale - ydelta);
2040
    yadd = .5 * (pin2 / scale - ydelta);
2041
    GScale(xmin - xadd, xmax + xadd, 1, dd);
2041
    GScale(xmin - xadd, xmax + xadd, 1, dd);
2042
    GScale(ymin - yadd, ymax + yadd, 2, dd);
2042
    GScale(ymin - yadd, ymax + yadd, 2, dd);
2043
    GMapWin2Fig(dd);
2043
    GMapWin2Fig(dd);
2044
}
2044
}
2045
 
2045
 
2046
static int LimitCheck(double *lim, double *c, double *s)
2046
static int LimitCheck(double *lim, double *c, double *s)
2047
{
2047
{
2048
    if (!R_FINITE(lim[0]) || !R_FINITE(lim[1]) || lim[0] >= lim[1])
2048
    if (!R_FINITE(lim[0]) || !R_FINITE(lim[1]) || lim[0] >= lim[1])
2049
	return 0;
2049
	return 0;
2050
    *s = 0.5 * fabs(lim[1] - lim[0]);
2050
    *s = 0.5 * fabs(lim[1] - lim[0]);
2051
    *c = 0.5 * (lim[1] + lim[0]);
2051
    *c = 0.5 * (lim[1] + lim[0]);
2052
    return 1;
2052
    return 1;
2053
}
2053
}
2054
 
2054
 
2055
/* PerspBox: The following code carries out a visibility test */
2055
/* PerspBox: The following code carries out a visibility test */
2056
/* on the surfaces of the xlim/ylim/zlim box around the plot. */
2056
/* on the surfaces of the xlim/ylim/zlim box around the plot. */
2057
/* If front = 0, only the faces with their inside toward the */
2057
/* If front = 0, only the faces with their inside toward the */
2058
/* eyepoint are drawn.  If front = 1, only the faces with */
2058
/* eyepoint are drawn.  If front = 1, only the faces with */
2059
/* their outside toward the eye are drawn.  This lets us carry */
2059
/* their outside toward the eye are drawn.  This lets us carry */
2060
/* out hidden line removal by drawing any faces which will be */
2060
/* out hidden line removal by drawing any faces which will be */
2061
/* obscured before the surface, and those which will not be */
2061
/* obscured before the surface, and those which will not be */
2062
/* obscured after the surface. */
2062
/* obscured after the surface. */
2063
 
2063
 
2064
/* The vertices of the box */
2064
/* The vertices of the box */
2065
static short int Vertex[8][3] = {
2065
static short int Vertex[8][3] = {
2066
    {0, 0, 0},
2066
    {0, 0, 0},
2067
    {0, 0, 1},
2067
    {0, 0, 1},
2068
    {0, 1, 0},
2068
    {0, 1, 0},
2069
    {0, 1, 1},
2069
    {0, 1, 1},
2070
    {1, 0, 0},
2070
    {1, 0, 0},
2071
    {1, 0, 1},
2071
    {1, 0, 1},
2072
    {1, 1, 0},
2072
    {1, 1, 0},
2073
    {1, 1, 1},
2073
    {1, 1, 1},
2074
};
2074
};
2075
 
2075
 
2076
/* The vertices visited when tracing a face */
2076
/* The vertices visited when tracing a face */
2077
static short int Face[6][4] = {
2077
static short int Face[6][4] = {
2078
    {0, 1, 5, 4},
2078
    {0, 1, 5, 4},
2079
    {2, 6, 7, 3},
2079
    {2, 6, 7, 3},
2080
    {0, 2, 3, 1},
2080
    {0, 2, 3, 1},
2081
    {4, 5, 7, 6},
2081
    {4, 5, 7, 6},
2082
    {0, 4, 6, 2},
2082
    {0, 4, 6, 2},
2083
    {1, 3, 7, 5},
2083
    {1, 3, 7, 5},
2084
};
2084
};
2085
 
2085
 
2086
/* The edges drawn when tracing a face */
2086
/* The edges drawn when tracing a face */
2087
static short int Edge[6][4] = {
2087
static short int Edge[6][4] = {
2088
    { 0, 1, 2, 3},
2088
    { 0, 1, 2, 3},
2089
    { 4, 5, 6, 7},
2089
    { 4, 5, 6, 7},
2090
    { 8, 7, 9, 0},
2090
    { 8, 7, 9, 0},
2091
    { 2,10, 5,11},
2091
    { 2,10, 5,11},
2092
    { 3,11, 4, 8},
2092
    { 3,11, 4, 8},
2093
    { 9, 6,10, 1},
2093
    { 9, 6,10, 1},
2094
};
2094
};
2095
 
2095
 
2096
/* Which edges have been drawn previously */
2096
/* Which edges have been drawn previously */
2097
static char EdgeDone[12];
2097
static char EdgeDone[12];
2098
 
2098
 
2099
static void PerspBox(int front, double *x, double *y, double *z, DevDesc *dd)
2099
static void PerspBox(int front, double *x, double *y, double *z, DevDesc *dd)
2100
{
2100
{
2101
    Vector3d u0, v0, u1, v1, u2, v2, u3, v3;
2101
    Vector3d u0, v0, u1, v1, u2, v2, u3, v3;
2102
    double d[3], e[3];
2102
    double d[3], e[3];
2103
    int f, i, p0, p1, p2, p3, nearby;
2103
    int f, i, p0, p1, p2, p3, nearby;
2104
    int ltysave = Rf_gpptr(dd)->lty;
2104
    int ltysave = Rf_gpptr(dd)->lty;
2105
    if (front)
2105
    if (front)
2106
	Rf_gpptr(dd)->lty = LTY_DOTTED;
2106
	Rf_gpptr(dd)->lty = LTY_DOTTED;
2107
    else
2107
    else
2108
	Rf_gpptr(dd)->lty = LTY_SOLID;
2108
	Rf_gpptr(dd)->lty = LTY_SOLID;
2109
    for (f = 0; f < 6; f++) {
2109
    for (f = 0; f < 6; f++) {
2110
        p0 = Face[f][0];
2110
        p0 = Face[f][0];
2111
        p1 = Face[f][1];
2111
        p1 = Face[f][1];
2112
        p2 = Face[f][2];
2112
        p2 = Face[f][2];
2113
        p3 = Face[f][3];
2113
        p3 = Face[f][3];
2114
 
2114
 
2115
	u0[0] = x[Vertex[p0][0]];
2115
	u0[0] = x[Vertex[p0][0]];
2116
	u0[1] = y[Vertex[p0][1]];
2116
	u0[1] = y[Vertex[p0][1]];
2117
	u0[2] = z[Vertex[p0][2]];
2117
	u0[2] = z[Vertex[p0][2]];
2118
	u0[3] = 1;
2118
	u0[3] = 1;
2119
	u1[0] = x[Vertex[p1][0]];
2119
	u1[0] = x[Vertex[p1][0]];
2120
	u1[1] = y[Vertex[p1][1]];
2120
	u1[1] = y[Vertex[p1][1]];
2121
	u1[2] = z[Vertex[p1][2]];
2121
	u1[2] = z[Vertex[p1][2]];
2122
	u1[3] = 1;
2122
	u1[3] = 1;
2123
	u2[0] = x[Vertex[p2][0]];
2123
	u2[0] = x[Vertex[p2][0]];
2124
	u2[1] = y[Vertex[p2][1]];
2124
	u2[1] = y[Vertex[p2][1]];
2125
	u2[2] = z[Vertex[p2][2]];
2125
	u2[2] = z[Vertex[p2][2]];
2126
	u2[3] = 1;
2126
	u2[3] = 1;
2127
	u3[0] = x[Vertex[p3][0]];
2127
	u3[0] = x[Vertex[p3][0]];
2128
	u3[1] = y[Vertex[p3][1]];
2128
	u3[1] = y[Vertex[p3][1]];
2129
	u3[2] = z[Vertex[p3][2]];
2129
	u3[2] = z[Vertex[p3][2]];
2130
	u3[3] = 1;
2130
	u3[3] = 1;
2131
 
2131
 
2132
	TransVector(u0, VT, v0);
2132
	TransVector(u0, VT, v0);
2133
	TransVector(u1, VT, v1);
2133
	TransVector(u1, VT, v1);
2134
	TransVector(u2, VT, v2);
2134
	TransVector(u2, VT, v2);
2135
	TransVector(u3, VT, v3);
2135
	TransVector(u3, VT, v3);
2136
 
2136
 
2137
	/* Visibility test. */
2137
	/* Visibility test. */
2138
	/* Determine whether the surface normal is toward the eye. */
2138
	/* Determine whether the surface normal is toward the eye. */
2139
	/* Note that we only draw lines once. */
2139
	/* Note that we only draw lines once. */
2140
 
2140
 
2141
        for (i = 0; i < 3; i++) {
2141
        for (i = 0; i < 3; i++) {
2142
	    d[i] = v1[i]/v1[3] - v0[i]/v0[3];
2142
	    d[i] = v1[i]/v1[3] - v0[i]/v0[3];
2143
	    e[i] = v2[i]/v2[3] - v1[i]/v1[3];
2143
	    e[i] = v2[i]/v2[3] - v1[i]/v1[3];
2144
        }
2144
        }
2145
	nearby = (d[0]*e[1] - d[1]*e[0]) < 0;
2145
	nearby = (d[0]*e[1] - d[1]*e[0]) < 0;
2146
 
2146
 
2147
	if ((front && nearby) || (!front && !nearby)) {
2147
	if ((front && nearby) || (!front && !nearby)) {
2148
	    if (!EdgeDone[Edge[f][0]]++)
2148
	    if (!EdgeDone[Edge[f][0]]++)
2149
		GLine(v0[0]/v0[3], v0[1]/v0[3],
2149
		GLine(v0[0]/v0[3], v0[1]/v0[3],
2150
		      v1[0]/v1[3], v1[1]/v1[3], USER, dd);
2150
		      v1[0]/v1[3], v1[1]/v1[3], USER, dd);
2151
	    if (!EdgeDone[Edge[f][1]]++)
2151
	    if (!EdgeDone[Edge[f][1]]++)
2152
		GLine(v1[0]/v1[3], v1[1]/v1[3],
2152
		GLine(v1[0]/v1[3], v1[1]/v1[3],
2153
		      v2[0]/v2[3], v2[1]/v2[3], USER, dd);
2153
		      v2[0]/v2[3], v2[1]/v2[3], USER, dd);
2154
	    if (!EdgeDone[Edge[f][2]]++)
2154
	    if (!EdgeDone[Edge[f][2]]++)
2155
		GLine(v2[0]/v2[3], v2[1]/v2[3],
2155
		GLine(v2[0]/v2[3], v2[1]/v2[3],
2156
		      v3[0]/v3[3], v3[1]/v3[3], USER, dd);
2156
		      v3[0]/v3[3], v3[1]/v3[3], USER, dd);
2157
	    if (!EdgeDone[Edge[f][3]]++)
2157
	    if (!EdgeDone[Edge[f][3]]++)
2158
		GLine(v3[0]/v3[3], v3[1]/v3[3],
2158
		GLine(v3[0]/v3[3], v3[1]/v3[3],
2159
		      v0[0]/v0[3], v0[1]/v0[3], USER, dd);
2159
		      v0[0]/v0[3], v0[1]/v0[3], USER, dd);
2160
	}
2160
	}
2161
    }
2161
    }
2162
    Rf_gpptr(dd)->lty = ltysave;
2162
    Rf_gpptr(dd)->lty = ltysave;
2163
}
2163
}
2164
 
2164
 
2165
/* PerspAxes:
2165
/* PerspAxes:
2166
 */
2166
 */
2167
 
2167
 
2168
/* Starting vertex for possible axes */
2168
/* Starting vertex for possible axes */
2169
static short int AxisStart[8] = { 0, 0, 2, 4, 0, 4, 2, 6 };
2169
static short int AxisStart[8] = { 0, 0, 2, 4, 0, 4, 2, 6 };
2170
 
2170
 
2171
/* Tick vector for possible axes */
2171
/* Tick vector for possible axes */
2172
static short int TickVector[8][3] = {
2172
static short int TickVector[8][3] = {
2173
    {0, -1, -1},
2173
    {0, -1, -1},
2174
    {-1, 0, -1},
2174
    {-1, 0, -1},
2175
    {0, 1, -1},
2175
    {0, 1, -1},
2176
    {1, 0, -1},
2176
    {1, 0, -1},
2177
    {-1, -1, 0},
2177
    {-1, -1, 0},
2178
    {1, -1, 0},
2178
    {1, -1, 0},
2179
    {-1, 1, 0},
2179
    {-1, 1, 0},
2180
    {1, 1, 0}};
2180
    {1, 1, 0}};
2181
 
2181
 
2182
static int lowest(double y1, double y2, double y3, double y4) {
2182
static int lowest(double y1, double y2, double y3, double y4) {
2183
    return ((y1 <= y2) && (y1 <= y3) && (y1 <= y4));
2183
    return ((y1 <= y2) && (y1 <= y3) && (y1 <= y4));
2184
}
2184
}
2185
 
2185
 
2186
static double labelAngle(double x1, double y1, double x2, double y2) {
2186
static double labelAngle(double x1, double y1, double x2, double y2) {
2187
    double dx, dy;
2187
    double dx, dy;
2188
    double angle;
2188
    double angle;
2189
    dx = fabs(x2 - x1);
2189
    dx = fabs(x2 - x1);
2190
    if (x2 > x1)
2190
    if (x2 > x1)
2191
	dy = y2 - y1;
2191
	dy = y2 - y1;
2192
    else
2192
    else
2193
	dy = y1 - y2;
2193
	dy = y1 - y2;
2194
    if (dx == 0) {
2194
    if (dx == 0) {
2195
	if (dy > 0)
2195
	if (dy > 0)
2196
	    angle = 90;
2196
	    angle = 90;
2197
	else
2197
	else
2198
	    angle = 270;
2198
	    angle = 270;
2199
    } else {
2199
    } else {
2200
	angle = (180 / M_PI) * atan2(dy, dx);
2200
	angle = (180 / M_PI) * atan2(dy, dx);
2201
    }
2201
    }
2202
    return angle;
2202
    return angle;
2203
}
2203
}
2204
 
2204
 
2205
static void PerspAxis(double *x, double *y, double *z,
2205
static void PerspAxis(double *x, double *y, double *z,
2206
		      int axis, int axisType, int nTicks, int tickType,
2206
		      int axis, int axisType, int nTicks, int tickType,
2207
		      const char *label, DevDesc *dd) {
2207
		      const char *label, DevDesc *dd) {
2208
    Vector3d u1, u2, u3, v1, v2, v3;
2208
    Vector3d u1, u2, u3, v1, v2, v3;
2209
    double tickLength = .03; /* proportion of axis length */
2209
    double tickLength = .03; /* proportion of axis length */
2210
    double min, max, d_frac;
2210
    double min, max, d_frac;
2211
    double *range = NULL; /* -Wall */
2211
    double *range = NULL; /* -Wall */
2212
    double axp[3];
2212
    double axp[3];
2213
    int nint, i;
2213
    int nint, i;
2214
    SEXP at, lab;
2214
    SEXP at, lab;
2215
    double cexsave = Rf_gpptr(dd)->cex;
2215
    double cexsave = Rf_gpptr(dd)->cex;
2216
    int fontsave = Rf_gpptr(dd)->font;
2216
    int fontsave = Rf_gpptr(dd)->font;
2217
 
2217
 
2218
 
2218
 
2219
    switch (axisType) {
2219
    switch (axisType) {
2220
    case 0:
2220
    case 0:
2221
	min = x[0];	max = x[1];	range = x;	break;
2221
	min = x[0];	max = x[1];	range = x;	break;
2222
    case 1:
2222
    case 1:
2223
	min = y[0];	max = y[1];	range = y;	break;
2223
	min = y[0];	max = y[1];	range = y;	break;
2224
    case 2:
2224
    case 2:
2225
	min = z[0];	max = z[1];	range = z;	break;
2225
	min = z[0];	max = z[1];	range = z;	break;
2226
    }
2226
    }
2227
    d_frac = 0.1*(max - min);
2227
    d_frac = 0.1*(max - min);
2228
    nint = nTicks - 1; if(!nint) nint++;
2228
    nint = nTicks - 1; if(!nint) nint++;
2229
    i = nint;
2229
    i = nint;
2230
    GPretty(&min, &max, &nint);
2230
    GPretty(&min, &max, &nint);
2231
    /* GPretty() rarely gives values too much outside range ..
2231
    /* GPretty() rarely gives values too much outside range ..
2232
       2D axis() clip these, we play cheaper */
2232
       2D axis() clip these, we play cheaper */
2233
    while((min < range[0] - d_frac || range[1] + d_frac < max) && i < 20) {
2233
    while((min < range[0] - d_frac || range[1] + d_frac < max) && i < 20) {
2234
	nint = ++i;
2234
	nint = ++i;
2235
	min = range[0];
2235
	min = range[0];
2236
	max = range[1];
2236
	max = range[1];
2237
	GPretty(&min, &max, &nint);
2237
	GPretty(&min, &max, &nint);
2238
    }
2238
    }
2239
    axp[0] = min;
2239
    axp[0] = min;
2240
    axp[1] = max;
2240
    axp[1] = max;
2241
    axp[2] = nint;
2241
    axp[2] = nint;
2242
    /* Do the following calculations for both ticktypes */
2242
    /* Do the following calculations for both ticktypes */
2243
    switch (axisType) {
2243
    switch (axisType) {
2244
    case 0:
2244
    case 0:
2245
	u1[0] = min;
2245
	u1[0] = min;
2246
	u1[1] = y[Vertex[AxisStart[axis]][1]];
2246
	u1[1] = y[Vertex[AxisStart[axis]][1]];
2247
	u1[2] = z[Vertex[AxisStart[axis]][2]];
2247
	u1[2] = z[Vertex[AxisStart[axis]][2]];
2248
	break;
2248
	break;
2249
    case 1:
2249
    case 1:
2250
	u1[0] = x[Vertex[AxisStart[axis]][0]];
2250
	u1[0] = x[Vertex[AxisStart[axis]][0]];
2251
	u1[1] = min;
2251
	u1[1] = min;
2252
	u1[2] = z[Vertex[AxisStart[axis]][2]];
2252
	u1[2] = z[Vertex[AxisStart[axis]][2]];
2253
	break;
2253
	break;
2254
    case 2:
2254
    case 2:
2255
	u1[0] = x[Vertex[AxisStart[axis]][0]];
2255
	u1[0] = x[Vertex[AxisStart[axis]][0]];
2256
	u1[1] = y[Vertex[AxisStart[axis]][1]];
2256
	u1[1] = y[Vertex[AxisStart[axis]][1]];
2257
	u1[2] = min;
2257
	u1[2] = min;
2258
	break;
2258
	break;
2259
    }
2259
    }
2260
    u1[0] = u1[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
2260
    u1[0] = u1[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
2261
    u1[1] = u1[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
2261
    u1[1] = u1[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
2262
    u1[2] = u1[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
2262
    u1[2] = u1[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
2263
    u1[3] = 1;
2263
    u1[3] = 1;
2264
    switch (axisType) {
2264
    switch (axisType) {
2265
    case 0:
2265
    case 0:
2266
	u2[0] = max;
2266
	u2[0] = max;
2267
	u2[1] = u1[1];
2267
	u2[1] = u1[1];
2268
	u2[2] = u1[2];
2268
	u2[2] = u1[2];
2269
	break;
2269
	break;
2270
    case 1:
2270
    case 1:
2271
	u2[0] = u1[0];
2271
	u2[0] = u1[0];
2272
	u2[1] = max;
2272
	u2[1] = max;
2273
	u2[2] = u1[2];
2273
	u2[2] = u1[2];
2274
	break;
2274
	break;
2275
    case 2:
2275
    case 2:
2276
	u2[0] = u1[0];
2276
	u2[0] = u1[0];
2277
	u2[1] = u1[1];
2277
	u2[1] = u1[1];
2278
	u2[2] = max;
2278
	u2[2] = max;
2279
	break;
2279
	break;
2280
    }
2280
    }
2281
    u2[3] = 1;
2281
    u2[3] = 1;
2282
    /* The axis label has to be further out for "detailed" ticks
2282
    /* The axis label has to be further out for "detailed" ticks
2283
       in order to leave room for the tick labels */
2283
       in order to leave room for the tick labels */
2284
    switch (tickType) {
2284
    switch (tickType) {
2285
    case 1: /* "simple": just an arrow parallel to axis, indicating direction
2285
    case 1: /* "simple": just an arrow parallel to axis, indicating direction
2286
	       of increase */
2286
	       of increase */
2287
	u3[0] = u1[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
2287
	u3[0] = u1[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
2288
	u3[1] = u1[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
2288
	u3[1] = u1[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
2289
	u3[2] = u1[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
2289
	u3[2] = u1[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
2290
	break;
2290
	break;
2291
    case 2:
2291
    case 2:
2292
	u3[0] = u1[0] + 2.5*tickLength*(x[1]-x[0])*TickVector[axis][0];
2292
	u3[0] = u1[0] + 2.5*tickLength*(x[1]-x[0])*TickVector[axis][0];
2293
	u3[1] = u1[1] + 2.5*tickLength*(y[1]-y[0])*TickVector[axis][1];
2293
	u3[1] = u1[1] + 2.5*tickLength*(y[1]-y[0])*TickVector[axis][1];
2294
	u3[2] = u1[2] + 2.5*tickLength*(z[1]-z[0])*TickVector[axis][2];
2294
	u3[2] = u1[2] + 2.5*tickLength*(z[1]-z[0])*TickVector[axis][2];
2295
	break;
2295
	break;
2296
    }
2296
    }
2297
    switch (axisType) {
2297
    switch (axisType) {
2298
    case 0:
2298
    case 0:
2299
	u3[0] = (min + max)/2;
2299
	u3[0] = (min + max)/2;
2300
	break;
2300
	break;
2301
    case 1:
2301
    case 1:
2302
	u3[1] = (min + max)/2;
2302
	u3[1] = (min + max)/2;
2303
	break;
2303
	break;
2304
    case 2:
2304
    case 2:
2305
	u3[2] = (min + max)/2;
2305
	u3[2] = (min + max)/2;
2306
	break;
2306
	break;
2307
    }
2307
    }
2308
    u3[3] = 1;
2308
    u3[3] = 1;
2309
    TransVector(u1, VT, v1);
2309
    TransVector(u1, VT, v1);
2310
    TransVector(u2, VT, v2);
2310
    TransVector(u2, VT, v2);
2311
    TransVector(u3, VT, v3);
2311
    TransVector(u3, VT, v3);
2312
    /* Draw axis label */
2312
    /* Draw axis label */
2313
    /* change in 2.5.0 to use cex.lab and font.lab */
2313
    /* change in 2.5.0 to use cex.lab and font.lab */
2314
    Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * Rf_gpptr(dd)->cexlab;
2314
    Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * Rf_gpptr(dd)->cexlab;
2315
    Rf_gpptr(dd)->font = Rf_gpptr(dd)->fontlab;
2315
    Rf_gpptr(dd)->font = Rf_gpptr(dd)->fontlab;
2316
    GText(v3[0]/v3[3], v3[1]/v3[3], USER, label, .5, .5,
2316
    GText(v3[0]/v3[3], v3[1]/v3[3], USER, label, .5, .5,
2317
	  labelAngle(v1[0]/v1[3], v1[1]/v1[3], v2[0]/v2[3], v2[1]/v2[3]),
2317
	  labelAngle(v1[0]/v1[3], v1[1]/v1[3], v2[0]/v2[3], v2[1]/v2[3]),
2318
	  dd);
2318
	  dd);
2319
    /* Draw axis ticks */
2319
    /* Draw axis ticks */
2320
    /* change in 2.5.0 to use cex.axis and font.axis */
2320
    /* change in 2.5.0 to use cex.axis and font.axis */
2321
    Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * Rf_gpptr(dd)->cexaxis;
2321
    Rf_gpptr(dd)->cex = Rf_gpptr(dd)->cexbase * Rf_gpptr(dd)->cexaxis;
2322
    Rf_gpptr(dd)->font = Rf_gpptr(dd)->fontaxis;
2322
    Rf_gpptr(dd)->font = Rf_gpptr(dd)->fontaxis;
2323
    switch (tickType) {
2323
    switch (tickType) {
2324
    case 1: /* "simple": just an arrow parallel to axis, indicating direction
2324
    case 1: /* "simple": just an arrow parallel to axis, indicating direction
2325
	       of increase */
2325
	       of increase */
2326
	/* arrow head is 0.25 inches long, with angle 30 degrees,
2326
	/* arrow head is 0.25 inches long, with angle 30 degrees,
2327
	   and drawn at v2 end of line */
2327
	   and drawn at v2 end of line */
2328
	GArrow(v1[0]/v1[3], v1[1]/v1[3],
2328
	GArrow(v1[0]/v1[3], v1[1]/v1[3],
2329
	       v2[0]/v2[3], v2[1]/v2[3], USER,
2329
	       v2[0]/v2[3], v2[1]/v2[3], USER,
2330
	       0.1, 10, 2, dd);
2330
	       0.1, 10, 2, dd);
2331
	break;
2331
	break;
2332
    case 2: /* "detailed": normal ticks as per 2D plots */
2332
    case 2: /* "detailed": normal ticks as per 2D plots */
2333
	PROTECT(at = CreateAtVector(axp, range, 7, FALSE));
2333
	PROTECT(at = CreateAtVector(axp, range, 7, FALSE));
2334
	PROTECT(lab = labelformat(at));
2334
	PROTECT(lab = labelformat(at));
2335
	for (i=0; i<length(at); i++) {
2335
	for (i=0; i<length(at); i++) {
2336
	    switch (axisType) {
2336
	    switch (axisType) {
2337
	    case 0:
2337
	    case 0:
2338
		u1[0] = REAL(at)[i];
2338
		u1[0] = REAL(at)[i];
2339
		u1[1] = y[Vertex[AxisStart[axis]][1]];
2339
		u1[1] = y[Vertex[AxisStart[axis]][1]];
2340
		u1[2] = z[Vertex[AxisStart[axis]][2]];
2340
		u1[2] = z[Vertex[AxisStart[axis]][2]];
2341
		break;
2341
		break;
2342
	    case 1:
2342
	    case 1:
2343
		u1[0] = x[Vertex[AxisStart[axis]][0]];
2343
		u1[0] = x[Vertex[AxisStart[axis]][0]];
2344
		u1[1] = REAL(at)[i];
2344
		u1[1] = REAL(at)[i];
2345
		u1[2] = z[Vertex[AxisStart[axis]][2]];
2345
		u1[2] = z[Vertex[AxisStart[axis]][2]];
2346
		break;
2346
		break;
2347
	    case 2:
2347
	    case 2:
2348
		u1[0] = x[Vertex[AxisStart[axis]][0]];
2348
		u1[0] = x[Vertex[AxisStart[axis]][0]];
2349
		u1[1] = y[Vertex[AxisStart[axis]][1]];
2349
		u1[1] = y[Vertex[AxisStart[axis]][1]];
2350
		u1[2] = REAL(at)[i];
2350
		u1[2] = REAL(at)[i];
2351
		break;
2351
		break;
2352
	    }
2352
	    }
2353
	    u1[3] = 1;
2353
	    u1[3] = 1;
2354
	    u2[0] = u1[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
2354
	    u2[0] = u1[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
2355
	    u2[1] = u1[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
2355
	    u2[1] = u1[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
2356
	    u2[2] = u1[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
2356
	    u2[2] = u1[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
2357
	    u2[3] = 1;
2357
	    u2[3] = 1;
2358
	    u3[0] = u2[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
2358
	    u3[0] = u2[0] + tickLength*(x[1]-x[0])*TickVector[axis][0];
2359
	    u3[1] = u2[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
2359
	    u3[1] = u2[1] + tickLength*(y[1]-y[0])*TickVector[axis][1];
2360
	    u3[2] = u2[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
2360
	    u3[2] = u2[2] + tickLength*(z[1]-z[0])*TickVector[axis][2];
2361
	    u3[3] = 1;
2361
	    u3[3] = 1;
2362
	    TransVector(u1, VT, v1);
2362
	    TransVector(u1, VT, v1);
2363
	    TransVector(u2, VT, v2);
2363
	    TransVector(u2, VT, v2);
2364
	    TransVector(u3, VT, v3);
2364
	    TransVector(u3, VT, v3);
2365
	    /* Draw tick line */
2365
	    /* Draw tick line */
2366
	    GLine(v1[0]/v1[3], v1[1]/v1[3],
2366
	    GLine(v1[0]/v1[3], v1[1]/v1[3],
2367
		  v2[0]/v2[3], v2[1]/v2[3], USER, dd);
2367
		  v2[0]/v2[3], v2[1]/v2[3], USER, dd);
2368
	    /* Draw tick label */
2368
	    /* Draw tick label */
2369
	    GText(v3[0]/v3[3], v3[1]/v3[3], USER,
2369
	    GText(v3[0]/v3[3], v3[1]/v3[3], USER,
2370
		  translateChar(STRING_ELT(lab, i)),
2370
		  translateChar(STRING_ELT(lab, i)),
2371
		  .5, .5, 0, dd);
2371
		  .5, .5, 0, dd);
2372
	}
2372
	}
2373
	UNPROTECT(2);
2373
	UNPROTECT(2);
2374
	break;
2374
	break;
2375
    }
2375
    }
2376
    Rf_gpptr(dd)->cex = cexsave;
2376
    Rf_gpptr(dd)->cex = cexsave;
2377
    Rf_gpptr(dd)->font = fontsave;
2377
    Rf_gpptr(dd)->font = fontsave;
2378
}
2378
}
2379
 
2379
 
2380
/* Determine the transformed (x, y) coordinates (in USER space)
2380
/* Determine the transformed (x, y) coordinates (in USER space)
2381
 * for the four corners of the x-y plane of the persp plot
2381
 * for the four corners of the x-y plane of the persp plot
2382
 * These will be used to determine which sides of the persp
2382
 * These will be used to determine which sides of the persp
2383
 * plot to label with axes
2383
 * plot to label with axes
2384
 * The strategy is to determine which corner has the lowest y-value
2384
 * The strategy is to determine which corner has the lowest y-value
2385
 * to decide which of the x- and y-axes to label AND which corner
2385
 * to decide which of the x- and y-axes to label AND which corner
2386
 * has the lowest x-value to decide which of the z-axes to label
2386
 * has the lowest x-value to decide which of the z-axes to label
2387
 */
2387
 */
2388
static void PerspAxes(double *x, double *y, double *z,
2388
static void PerspAxes(double *x, double *y, double *z,
2389
                      const char *xlab, const char *ylab, const char *zlab,
2389
                      const char *xlab, const char *ylab, const char *zlab,
2390
		      int nTicks, int tickType, DevDesc *dd) {
2390
		      int nTicks, int tickType, DevDesc *dd) {
2391
    int xAxis=0, yAxis=0, zAxis=0; /* -Wall */
2391
    int xAxis=0, yAxis=0, zAxis=0; /* -Wall */
2392
    int xpdsave;
2392
    int xpdsave;
2393
    Vector3d u0, u1, u2, u3;
2393
    Vector3d u0, u1, u2, u3;
2394
    Vector3d v0, v1, v2, v3;
2394
    Vector3d v0, v1, v2, v3;
2395
    u0[0] = x[0];
2395
    u0[0] = x[0];
2396
    u0[1] = y[0];
2396
    u0[1] = y[0];
2397
    u0[2] = z[0];
2397
    u0[2] = z[0];
2398
    u0[3] = 1;
2398
    u0[3] = 1;
2399
    u1[0] = x[1];
2399
    u1[0] = x[1];
2400
    u1[1] = y[0];
2400
    u1[1] = y[0];
2401
    u1[2] = z[0];
2401
    u1[2] = z[0];
2402
    u1[3] = 1;
2402
    u1[3] = 1;
2403
    u2[0] = x[0];
2403
    u2[0] = x[0];
2404
    u2[1] = y[1];
2404
    u2[1] = y[1];
2405
    u2[2] = z[0];
2405
    u2[2] = z[0];
2406
    u2[3] = 1;
2406
    u2[3] = 1;
2407
    u3[0] = x[1];
2407
    u3[0] = x[1];
2408
    u3[1] = y[1];
2408
    u3[1] = y[1];
2409
    u3[2] = z[0];
2409
    u3[2] = z[0];
2410
    u3[3] = 1;
2410
    u3[3] = 1;
2411
    TransVector(u0, VT, v0);
2411
    TransVector(u0, VT, v0);
2412
    TransVector(u1, VT, v1);
2412
    TransVector(u1, VT, v1);
2413
    TransVector(u2, VT, v2);
2413
    TransVector(u2, VT, v2);
2414
    TransVector(u3, VT, v3);
2414
    TransVector(u3, VT, v3);
2415
 
2415
 
2416
    /* to fit in the axis labels */
2416
    /* to fit in the axis labels */
2417
    xpdsave = Rf_gpptr(dd)->xpd;
2417
    xpdsave = Rf_gpptr(dd)->xpd;
2418
    Rf_gpptr(dd)->xpd = 1;
2418
    Rf_gpptr(dd)->xpd = 1;
2419
 
2419
 
2420
    /* Figure out which X and Y axis to draw */
2420
    /* Figure out which X and Y axis to draw */
2421
    if (lowest(v0[1]/v0[3], v1[1]/v1[3], v2[1]/v2[3], v3[1]/v3[3])) {
2421
    if (lowest(v0[1]/v0[3], v1[1]/v1[3], v2[1]/v2[3], v3[1]/v3[3])) {
2422
	xAxis = 0;
2422
	xAxis = 0;
2423
	yAxis = 1;
2423
	yAxis = 1;
2424
    } else if (lowest(v1[1]/v1[3], v0[1]/v0[3], v2[1]/v2[3], v3[1]/v3[3])) {
2424
    } else if (lowest(v1[1]/v1[3], v0[1]/v0[3], v2[1]/v2[3], v3[1]/v3[3])) {
2425
	xAxis = 0;
2425
	xAxis = 0;
2426
	yAxis = 3;
2426
	yAxis = 3;
2427
    } else if (lowest(v2[1]/v2[3], v1[1]/v1[3], v0[1]/v0[3], v3[1]/v3[3])) {
2427
    } else if (lowest(v2[1]/v2[3], v1[1]/v1[3], v0[1]/v0[3], v3[1]/v3[3])) {
2428
	xAxis = 2;
2428
	xAxis = 2;
2429
	yAxis = 1;
2429
	yAxis = 1;
2430
    } else if (lowest(v3[1]/v3[3], v1[1]/v1[3], v2[1]/v2[3], v0[1]/v0[3])) {
2430
    } else if (lowest(v3[1]/v3[3], v1[1]/v1[3], v2[1]/v2[3], v0[1]/v0[3])) {
2431
	xAxis = 2;
2431
	xAxis = 2;
2432
	yAxis = 3;
2432
	yAxis = 3;
2433
    } else
2433
    } else
2434
	warning(_("Axis orientation not calculated"));
2434
	warning(_("Axis orientation not calculated"));
2435
    PerspAxis(x, y, z, xAxis, 0, nTicks, tickType, xlab, dd);
2435
    PerspAxis(x, y, z, xAxis, 0, nTicks, tickType, xlab, dd);
2436
    PerspAxis(x, y, z, yAxis, 1, nTicks, tickType, ylab, dd);
2436
    PerspAxis(x, y, z, yAxis, 1, nTicks, tickType, ylab, dd);
2437
    /* Figure out which Z axis to draw */
2437
    /* Figure out which Z axis to draw */
2438
    if (lowest(v0[0]/v0[3], v1[0]/v1[3], v2[0]/v2[3], v3[0]/v3[3])) {
2438
    if (lowest(v0[0]/v0[3], v1[0]/v1[3], v2[0]/v2[3], v3[0]/v3[3])) {
2439
	zAxis = 4;
2439
	zAxis = 4;
2440
    } else if (lowest(v1[0]/v1[3], v0[0]/v0[3], v2[0]/v2[3], v3[0]/v3[3])) {
2440
    } else if (lowest(v1[0]/v1[3], v0[0]/v0[3], v2[0]/v2[3], v3[0]/v3[3])) {
2441
	zAxis = 5;
2441
	zAxis = 5;
2442
    } else if (lowest(v2[0]/v2[3], v1[0]/v1[3], v0[0]/v0[3], v3[0]/v3[3])) {
2442
    } else if (lowest(v2[0]/v2[3], v1[0]/v1[3], v0[0]/v0[3], v3[0]/v3[3])) {
2443
	zAxis = 6;
2443
	zAxis = 6;
2444
    } else if (lowest(v3[0]/v3[3], v1[0]/v1[3], v2[0]/v2[3], v0[0]/v0[3])) {
2444
    } else if (lowest(v3[0]/v3[3], v1[0]/v1[3], v2[0]/v2[3], v0[0]/v0[3])) {
2445
	zAxis = 7;
2445
	zAxis = 7;
2446
    } else
2446
    } else
2447
	warning(_("Axis orientation not calculated"));
2447
	warning(_("Axis orientation not calculated"));
2448
    PerspAxis(x, y, z, zAxis, 2, nTicks, tickType, zlab, dd);
2448
    PerspAxis(x, y, z, zAxis, 2, nTicks, tickType, zlab, dd);
2449
 
2449
 
2450
    Rf_gpptr(dd)->xpd = xpdsave;
2450
    Rf_gpptr(dd)->xpd = xpdsave;
2451
}
2451
}
2452
 
2452
 
2453
SEXP attribute_hidden do_persp(SEXP call, SEXP op, SEXP args, SEXP env)
2453
SEXP attribute_hidden do_persp(SEXP call, SEXP op, SEXP args, SEXP env)
2454
{
2454
{
2455
    SEXP x, y, z, xlim, ylim, zlim;
2455
    SEXP x, y, z, xlim, ylim, zlim;
2456
    SEXP depth, indx, originalArgs;
2456
    SEXP depth, indx, originalArgs;
2457
    SEXP col, border, xlab, ylab, zlab;
2457
    SEXP col, border, xlab, ylab, zlab;
2458
    double theta, phi, r, d;
2458
    double theta, phi, r, d;
2459
    double ltheta, lphi;
2459
    double ltheta, lphi;
2460
    double expand, xc = 0.0, yc = 0.0, zc = 0.0, xs = 0.0, ys = 0.0, zs = 0.0;
2460
    double expand, xc = 0.0, yc = 0.0, zc = 0.0, xs = 0.0, ys = 0.0, zs = 0.0;
2461
    int i, j, scale, ncol, dobox, doaxes, nTicks, tickType;
2461
    int i, j, scale, ncol, dobox, doaxes, nTicks, tickType;
2462
    DevDesc *dd;
2462
    DevDesc *dd;
2463
 
2463
 
2464
    if (length(args) < 24)
2464
    if (length(args) < 24)
2465
	error(_("too few parameters"));
2465
	error(_("too few parameters"));
2466
    gcall = call;
2466
    gcall = call;
2467
    originalArgs = args;
2467
    originalArgs = args;
2468
 
2468
 
2469
    PROTECT(x = coerceVector(CAR(args), REALSXP));
2469
    PROTECT(x = coerceVector(CAR(args), REALSXP));
2470
    if (length(x) < 2) error(_("invalid '%s' argument"), "x");
2470
    if (length(x) < 2) error(_("invalid '%s' argument"), "x");
2471
    args = CDR(args);
2471
    args = CDR(args);
2472
 
2472
 
2473
    PROTECT(y = coerceVector(CAR(args), REALSXP));
2473
    PROTECT(y = coerceVector(CAR(args), REALSXP));
2474
    if (length(y) < 2) error(_("invalid '%s' argument"), "x");
2474
    if (length(y) < 2) error(_("invalid '%s' argument"), "x");
2475
    args = CDR(args);
2475
    args = CDR(args);
2476
 
2476
 
2477
    PROTECT(z = coerceVector(CAR(args), REALSXP));
2477
    PROTECT(z = coerceVector(CAR(args), REALSXP));
2478
    if (!isMatrix(z) || nrows(z) != length(x) || ncols(z) != length(y))
2478
    if (!isMatrix(z) || nrows(z) != length(x) || ncols(z) != length(y))
2479
	error(_("invalid '%s' argument"), "z");
2479
	error(_("invalid '%s' argument"), "z");
2480
    args = CDR(args);
2480
    args = CDR(args);
2481
 
2481
 
2482
    PROTECT(xlim = coerceVector(CAR(args), REALSXP));
2482
    PROTECT(xlim = coerceVector(CAR(args), REALSXP));
2483
    if (length(xlim) != 2) error(_("invalid '%s' argument"), "xlim");
2483
    if (length(xlim) != 2) error(_("invalid '%s' argument"), "xlim");
2484
    args = CDR(args);
2484
    args = CDR(args);
2485
 
2485
 
2486
    PROTECT(ylim = coerceVector(CAR(args), REALSXP));
2486
    PROTECT(ylim = coerceVector(CAR(args), REALSXP));
2487
    if (length(ylim) != 2) error(_("invalid '%s' argument"), "ylim");
2487
    if (length(ylim) != 2) error(_("invalid '%s' argument"), "ylim");
2488
    args = CDR(args);
2488
    args = CDR(args);
2489
 
2489
 
2490
    PROTECT(zlim = coerceVector(CAR(args), REALSXP));
2490
    PROTECT(zlim = coerceVector(CAR(args), REALSXP));
2491
    if (length(zlim) != 2) error(_("invalid '%s' argument"), "zlim");
2491
    if (length(zlim) != 2) error(_("invalid '%s' argument"), "zlim");
2492
    args = CDR(args);
2492
    args = CDR(args);
2493
 
2493
 
2494
    /* Checks on x/y/z Limits */
2494
    /* Checks on x/y/z Limits */
2495
 
2495
 
2496
    if (!LimitCheck(REAL(xlim), &xc, &xs))
2496
    if (!LimitCheck(REAL(xlim), &xc, &xs))
2497
	error(_("invalid 'x' limits"));
2497
	error(_("invalid 'x' limits"));
2498
    if (!LimitCheck(REAL(ylim), &yc, &ys))
2498
    if (!LimitCheck(REAL(ylim), &yc, &ys))
2499
	error(_("invalid 'y' limits"));
2499
	error(_("invalid 'y' limits"));
2500
    if (!LimitCheck(REAL(zlim), &zc, &zs))
2500
    if (!LimitCheck(REAL(zlim), &zc, &zs))
2501
	error(_("invalid 'z' limits"));
2501
	error(_("invalid 'z' limits"));
2502
 
2502
 
2503
    theta = asReal(CAR(args));	args = CDR(args);
2503
    theta = asReal(CAR(args));	args = CDR(args);
2504
    phi	  = asReal(CAR(args));	args = CDR(args);
2504
    phi	  = asReal(CAR(args));	args = CDR(args);
2505
    r	= asReal(CAR(args));	args = CDR(args);
2505
    r	= asReal(CAR(args));	args = CDR(args);
2506
    d	= asReal(CAR(args));	args = CDR(args);
2506
    d	= asReal(CAR(args));	args = CDR(args);
2507
    scale  = asLogical(CAR(args)); args = CDR(args);
2507
    scale  = asLogical(CAR(args)); args = CDR(args);
2508
    expand = asReal(CAR(args)); args = CDR(args);
2508
    expand = asReal(CAR(args)); args = CDR(args);
2509
    col	   = CAR(args);		args = CDR(args);
2509
    col	   = CAR(args);		args = CDR(args);
2510
    border = CAR(args);		args = CDR(args);
2510
    border = CAR(args);		args = CDR(args);
2511
    ltheta = asReal(CAR(args)); args = CDR(args);
2511
    ltheta = asReal(CAR(args)); args = CDR(args);
2512
    lphi   = asReal(CAR(args)); args = CDR(args);
2512
    lphi   = asReal(CAR(args)); args = CDR(args);
2513
    Shade  = asReal(CAR(args)); args = CDR(args);
2513
    Shade  = asReal(CAR(args)); args = CDR(args);
2514
    dobox  = asLogical(CAR(args)); args = CDR(args);
2514
    dobox  = asLogical(CAR(args)); args = CDR(args);
2515
    doaxes = asLogical(CAR(args)); args = CDR(args);
2515
    doaxes = asLogical(CAR(args)); args = CDR(args);
2516
    nTicks = asInteger(CAR(args)); args = CDR(args);
2516
    nTicks = asInteger(CAR(args)); args = CDR(args);
2517
    tickType = asInteger(CAR(args)); args = CDR(args);
2517
    tickType = asInteger(CAR(args)); args = CDR(args);
2518
    xlab = CAR(args); args = CDR(args);
2518
    xlab = CAR(args); args = CDR(args);
2519
    ylab = CAR(args); args = CDR(args);
2519
    ylab = CAR(args); args = CDR(args);
2520
    zlab = CAR(args); args = CDR(args);
2520
    zlab = CAR(args); args = CDR(args);
2521
    if (!isString(xlab) || length(xlab) < 1)
2521
    if (!isString(xlab) || length(xlab) < 1)
2522
	error(_("'xlab' must be a character vector of length 1"));
2522
	error(_("'xlab' must be a character vector of length 1"));
2523
    if (!isString(ylab) || length(ylab) < 1)
2523
    if (!isString(ylab) || length(ylab) < 1)
2524
	error(_("'ylab' must be a character vector of length 1"));
2524
	error(_("'ylab' must be a character vector of length 1"));
2525
    if (!isString(zlab) || length(zlab) < 1)
2525
    if (!isString(zlab) || length(zlab) < 1)
2526
	error(_("'zlab' must be a character vector of length 1"));
2526
	error(_("'zlab' must be a character vector of length 1"));
2527
 
2527
 
2528
    if (R_FINITE(Shade) && Shade <= 0) Shade = 1;
2528
    if (R_FINITE(Shade) && Shade <= 0) Shade = 1;
2529
    if (R_FINITE(ltheta) && R_FINITE(lphi) && R_FINITE(Shade))
2529
    if (R_FINITE(ltheta) && R_FINITE(lphi) && R_FINITE(Shade))
2530
	DoLighting = TRUE;
2530
	DoLighting = TRUE;
2531
    else
2531
    else
2532
	DoLighting = FALSE;
2532
	DoLighting = FALSE;
2533
 
2533
 
2534
    if (!scale) {
2534
    if (!scale) {
2535
	double s;
2535
	double s;
2536
	s = xs;
2536
	s = xs;
2537
	if (s < ys) s = ys;
2537
	if (s < ys) s = ys;
2538
	if (s < zs) s = zs;
2538
	if (s < zs) s = zs;
2539
	xs = s; ys = s; zs = s;
2539
	xs = s; ys = s; zs = s;
2540
    }
2540
    }
2541
 
2541
 
2542
    /* Parameter Checks */
2542
    /* Parameter Checks */
2543
 
2543
 
2544
    if (!R_FINITE(theta) || !R_FINITE(phi) || !R_FINITE(r) || !R_FINITE(d) ||
2544
    if (!R_FINITE(theta) || !R_FINITE(phi) || !R_FINITE(r) || !R_FINITE(d) ||
2545
	d < 0 || r < 0)
2545
	d < 0 || r < 0)
2546
	error(_("invalid viewing parameters"));
2546
	error(_("invalid viewing parameters"));
2547
    if (!R_FINITE(expand) || expand < 0)
2547
    if (!R_FINITE(expand) || expand < 0)
2548
	error(_("invalid '%s' value"), "expand");
2548
	error(_("invalid '%s' value"), "expand");
2549
    if (scale == NA_LOGICAL)
2549
    if (scale == NA_LOGICAL)
2550
	scale = 0;
2550
	scale = 0;
2551
    if ((nTicks == NA_INTEGER) || (nTicks < 0))
2551
    if ((nTicks == NA_INTEGER) || (nTicks < 0))
2552
	error(_("invalid '%s' value"), "nticks");
2552
	error(_("invalid '%s' value"), "nticks");
2553
    if ((tickType == NA_INTEGER) || (tickType < 1) || (tickType > 2))
2553
    if ((tickType == NA_INTEGER) || (tickType < 1) || (tickType > 2))
2554
	error(_("invalid '%s' value"), "ticktype");
2554
	error(_("invalid '%s' value"), "ticktype");
2555
 
2555
 
2556
    dd = CurrentDevice();
2556
    dd = CurrentDevice();
2557
 
2557
 
2558
    GNewPlot(GRecording(call, dd));
2558
    GNewPlot(GRecording(call, dd));
2559
 
2559
 
2560
    PROTECT(col = FixupCol(col, Rf_gpptr(dd)->bg));
2560
    PROTECT(col = FixupCol(col, Rf_gpptr(dd)->bg));
2561
    ncol = LENGTH(col);
2561
    ncol = LENGTH(col);
2562
    if (ncol < 1) error(_("invalid '%s' specification"), "col");
2562
    if (ncol < 1) error(_("invalid '%s' specification"), "col");
2563
    if(!R_OPAQUE(INTEGER(col)[0])) DoLighting = FALSE;
2563
    if(!R_OPAQUE(INTEGER(col)[0])) DoLighting = FALSE;
2564
    PROTECT(border = FixupCol(border, Rf_gpptr(dd)->fg));
2564
    PROTECT(border = FixupCol(border, Rf_gpptr(dd)->fg));
2565
    if (length(border) < 1) 
2565
    if (length(border) < 1) 
2566
	error(_("invalid '%s' specification"), "border");
2566
	error(_("invalid '%s' specification"), "border");
2567
 
2567
 
2568
    GSetState(1, dd);
2568
    GSetState(1, dd);
2569
    GSavePars(dd);
2569
    GSavePars(dd);
2570
    ProcessInlinePars(args, dd, call);
2570
    ProcessInlinePars(args, dd, call);
2571
    if (length(border) > 1)
2571
    if (length(border) > 1)
2572
	Rf_gpptr(dd)->fg = INTEGER(border)[0];
2572
	Rf_gpptr(dd)->fg = INTEGER(border)[0];
2573
    Rf_gpptr(dd)->xlog = Rf_gpptr(dd)->ylog = FALSE;
2573
    Rf_gpptr(dd)->xlog = Rf_gpptr(dd)->ylog = FALSE;
2574
 
2574
 
2575
    /* Set up the light vector (if any) */
2575
    /* Set up the light vector (if any) */
2576
    if (DoLighting)
2576
    if (DoLighting)
2577
        SetUpLight(ltheta, lphi);
2577
        SetUpLight(ltheta, lphi);
2578
 
2578
 
2579
    /* Mark box edges as undrawn */
2579
    /* Mark box edges as undrawn */
2580
    for (i = 0; i< 12; i++)
2580
    for (i = 0; i< 12; i++)
2581
	EdgeDone[i] = 0;
2581
	EdgeDone[i] = 0;
2582
 
2582
 
2583
    /* Specify the viewing transformation. */
2583
    /* Specify the viewing transformation. */
2584
 
2584
 
2585
    SetToIdentity(VT);             /* Initialization */
2585
    SetToIdentity(VT);             /* Initialization */
2586
    Translate(-xc, -yc, -zc);      /* center at the origin */
2586
    Translate(-xc, -yc, -zc);      /* center at the origin */
2587
    Scale(1/xs, 1/ys, expand/zs);  /* scale extents to [-1,1] */
2587
    Scale(1/xs, 1/ys, expand/zs);  /* scale extents to [-1,1] */
2588
    XRotate(-90.0);                /* rotate x-y plane to horizontal */
2588
    XRotate(-90.0);                /* rotate x-y plane to horizontal */
2589
    YRotate(-theta);               /* azimuthal rotation */
2589
    YRotate(-theta);               /* azimuthal rotation */
2590
    XRotate(phi);                  /* elevation rotation */
2590
    XRotate(phi);                  /* elevation rotation */
2591
    Translate(0.0, 0.0, -r - d);   /* translate the eyepoint to the origin */
2591
    Translate(0.0, 0.0, -r - d);   /* translate the eyepoint to the origin */
2592
    Perspective(d);                /* perspective */
2592
    Perspective(d);                /* perspective */
2593
 
2593
 
2594
    /* Specify the plotting window. */
2594
    /* Specify the plotting window. */
2595
    /* Here we map the vertices of the cube */
2595
    /* Here we map the vertices of the cube */
2596
    /* [xmin,xmax]*[ymin,ymax]*[zmin,zmax] */
2596
    /* [xmin,xmax]*[ymin,ymax]*[zmin,zmax] */
2597
    /* to the screen and then chose a window */
2597
    /* to the screen and then chose a window */
2598
    /* which is symmetric about (0,0). */
2598
    /* which is symmetric about (0,0). */
2599
 
2599
 
2600
    PerspWindow(REAL(xlim), REAL(ylim), REAL(zlim), dd);
2600
    PerspWindow(REAL(xlim), REAL(ylim), REAL(zlim), dd);
2601
 
2601
 
2602
    /* Compute facet order. */
2602
    /* Compute facet order. */
2603
 
2603
 
2604
    PROTECT(depth = allocVector(REALSXP, (nrows(z) - 1)*(ncols(z) - 1)));
2604
    PROTECT(depth = allocVector(REALSXP, (nrows(z) - 1)*(ncols(z) - 1)));
2605
    PROTECT(indx = allocVector(INTSXP, (nrows(z) - 1)*(ncols(z) - 1)));
2605
    PROTECT(indx = allocVector(INTSXP, (nrows(z) - 1)*(ncols(z) - 1)));
2606
    DepthOrder(REAL(z), REAL(x), REAL(y), nrows(z), ncols(z),
2606
    DepthOrder(REAL(z), REAL(x), REAL(y), nrows(z), ncols(z),
2607
	       REAL(depth), INTEGER(indx));
2607
	       REAL(depth), INTEGER(indx));
2608
 
2608
 
2609
    /* Now we order the facets by depth and then draw them back to front.
2609
    /* Now we order the facets by depth and then draw them back to front.
2610
     * This is the "painters" algorithm. */
2610
     * This is the "painters" algorithm. */
2611
 
2611
 
2612
    GMode(1, dd);
2612
    GMode(1, dd);
2613
 
2613
 
2614
    if (dobox) {
2614
    if (dobox) {
2615
        PerspBox(0, REAL(xlim), REAL(ylim), REAL(zlim), dd);
2615
        PerspBox(0, REAL(xlim), REAL(ylim), REAL(zlim), dd);
2616
	if (doaxes) {
2616
	if (doaxes) {
2617
	    SEXP xl = STRING_ELT(xlab, 0), yl = STRING_ELT(ylab, 0),
2617
	    SEXP xl = STRING_ELT(xlab, 0), yl = STRING_ELT(ylab, 0),
2618
		zl = STRING_ELT(zlab, 0);
2618
		zl = STRING_ELT(zlab, 0);
2619
	    PerspAxes(REAL(xlim), REAL(ylim), REAL(zlim),
2619
	    PerspAxes(REAL(xlim), REAL(ylim), REAL(zlim),
2620
		      (xl == NA_STRING)? "" : translateChar(xl),
2620
		      (xl == NA_STRING)? "" : translateChar(xl),
2621
		      (yl == NA_STRING)? "" : translateChar(yl),
2621
		      (yl == NA_STRING)? "" : translateChar(yl),
2622
		      (zl == NA_STRING)? "" : translateChar(zl),
2622
		      (zl == NA_STRING)? "" : translateChar(zl),
2623
		      nTicks, tickType, dd);
2623
		      nTicks, tickType, dd);
2624
	}
2624
	}
2625
    }
2625
    }
2626
 
2626
 
2627
    DrawFacets(REAL(z), REAL(x), REAL(y), nrows(z), ncols(z), INTEGER(indx),
2627
    DrawFacets(REAL(z), REAL(x), REAL(y), nrows(z), ncols(z), INTEGER(indx),
2628
	       1/xs, 1/ys, expand/zs,
2628
	       1/xs, 1/ys, expand/zs,
2629
	       INTEGER(col), ncol, INTEGER(border)[0]);
2629
	       INTEGER(col), ncol, INTEGER(border)[0]);
2630
 
2630
 
2631
    if (dobox)
2631
    if (dobox)
2632
        PerspBox(1, REAL(xlim), REAL(ylim), REAL(zlim), dd);
2632
        PerspBox(1, REAL(xlim), REAL(ylim), REAL(zlim), dd);
2633
    GMode(0, dd);
2633
    GMode(0, dd);
2634
 
2634
 
2635
    GRestorePars(dd);
2635
    GRestorePars(dd);
2636
    UNPROTECT(10);
2636
    UNPROTECT(10);
2637
    if (GRecording(call, dd))
2637
    if (GRecording(call, dd))
2638
        recordGraphicOperation(op, originalArgs, dd);
2638
        recordGraphicOperation(op, originalArgs, dd);
2639
 
2639
 
2640
    PROTECT(x = allocVector(REALSXP, 16));
2640
    PROTECT(x = allocVector(REALSXP, 16));
2641
    PROTECT(y = allocVector(INTSXP, 2));
2641
    PROTECT(y = allocVector(INTSXP, 2));
2642
    for (i = 0; i < 4; i++)
2642
    for (i = 0; i < 4; i++)
2643
	for (j = 0; j < 4; j++)
2643
	for (j = 0; j < 4; j++)
2644
	    REAL(x)[i + j * 4] = VT[i][j];
2644
	    REAL(x)[i + j * 4] = VT[i][j];
2645
    INTEGER(y)[0] = 4;
2645
    INTEGER(y)[0] = 4;
2646
    INTEGER(y)[1] = 4;
2646
    INTEGER(y)[1] = 4;
2647
    setAttrib(x, R_DimSymbol, y);
2647
    setAttrib(x, R_DimSymbol, y);
2648
    UNPROTECT(2);
2648
    UNPROTECT(2);
2649
    return x;
2649
    return x;
2650
}
2650
}
2651
 
2651