The R Project SVN R

Rev

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

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